Programmēšana

4 izplatītas C programmēšanas kļūdas - un 5 padomi, kā no tām izvairīties

Tikai dažas programmēšanas valodas var atbilst C, lai iegūtu milzīgu ātrumu un iekārtas līmeņa jaudu. Šis apgalvojums bija patiess pirms 50 gadiem un ir taisnība arī šodien. Tomēr ir iemesls, kāpēc programmētāji izdomāja terminu “kājiņa”, lai aprakstītu C veida spēku. Ja neesat piesardzīgs, C var izpūst jūsu vai kāda cita pirkstus.

Šeit ir četras visizplatītākās kļūdas, kuras varat pieļaut ar C, un pieci soļi, kurus varat veikt, lai tos novērstu.

Bieža C kļūda: neatbrīvo mallocatmiņa (vai tās atbrīvošana vairāk nekā vienu reizi)

Šī ir viena no lielākajām kļūdām C, no kurām daudzas ir saistītas ar atmiņas pārvaldību. Piešķirtā atmiņa (izdarīta, izmantojot malloc funkcija) netiek automātiski iznīcināta C. Tas ir programmētāja uzdevums atbrīvoties no šīs atmiņas, kad tā vairs netiek izmantota. Neizdodas atbrīvot atkārtotus atmiņas pieprasījumus, un galu galā rodas atmiņas noplūde. Mēģiniet izmantot atmiņas reģionu, kas jau ir atbrīvots, un jūsu programma avarēs - vai, vēl ļaunāk, tā klibos un kļūs neaizsargāta pret uzbrukumu, izmantojot šo mehānismu.

Ņemiet vērā, ka atmiņa noplūde vajadzētu aprakstīt tikai situācijas, kurās atmiņa ir domājams atbrīvoties, bet nav. Ja programma turpina piešķirt atmiņu, jo atmiņa faktiski ir nepieciešama un izmantota darbam, tad tā var būt atmiņas izmantošananeefektīvs, bet stingri runājot, tā nav noplūde.

Bieža C kļūda: masīva lasīšana ārpus robežām

Šeit mums ir vēl viena no visbiežāk sastopamajām un bīstamākajām kļūdām C. Lasot aiz masīva beigām, var atgriezt atkritumu datus. Rakstīšana gar masīva robežām var sabojāt programmas stāvokli vai pilnībā sabojāt to vai, pats ļaunākais, kļūt par ļaunprātīgas programmatūras uzbrukuma vektoru.

Tātad, kāpēc masīva robežu pārbaudes nasta tiek atstāta programmētājam? Oficiālajā C specifikācijā masīva lasīšana vai rakstīšana ārpus tā robežām ir “nedefinēta rīcība”, kas nozīmē, ka specam nav teikšanas par to, kam vajadzētu notikt. Sastādītājam pat nav jāsūdzas par to.

C jau sen ir atbalstījis programmētāja pilnvaru piešķiršanu pat uz viņu pašu risku. Kompilators parasti nenoķer neierobežotu lasīšanu vai rakstīšanu, ja vien jūs īpaši neiespējojat kompilatora opcijas, lai to aizsargātu. Turklāt var būt iespējams, ka izpildlaika laikā tiek pārsniegta masīva robeža tādā veidā, no kura nevar aizsargāties pat kompilatora pārbaude.

Bieža C kļūda: nepārbauda malloc

malloc un calloc (iepriekš nulles atmiņai) ir C bibliotēkas funkcijas, kas no sistēmas iegūst kaudzēm piešķirto atmiņu. Ja viņi nespēj piešķirt atmiņu, tie rada kļūdu. Tajos laikos, kad datoriem bija salīdzinoši maz atmiņas, bija diezgan liela iespēja piezvanīt malloc var neizdoties.

Lai gan datoriem mūsdienās ir gigabaitu RAM, ko izmest, joprojām pastāv iespēja malloc var neizdoties, jo īpaši zem liela atmiņas spiediena vai vienlaikus piešķirot lielas atmiņas plāksnes. Tas jo īpaši attiecas uz C programmām, kas vispirms “sadala” lielu atmiņas bloku no OS un pēc tam sadala savām vajadzībām. Ja šī pirmā piešķiršana neizdodas, jo tā ir pārāk liela, jūs, iespējams, varēsit notvert šo atteikumu, samazināt sadalījumu un attiecīgi pielāgot programmas atmiņas izmantošanas heiristiku. Bet, ja atmiņas piešķiršana neizdodas notvert, visa programma var kļūt par vēderu uz augšu.

Bieža C kļūda: Izmantojot spēkā neesošs * vispārīgiem rādītājiem atmiņā

Izmantojotspēkā neesošs * norādīt uz atmiņu ir sens ieradums - un slikts. Norādēm uz atmiņu vienmēr jābūt char *, neparakstīta rakstzīme *vaiuintptr_t *. Mūsdienu C kompilatoru komplektiem vajadzētu nodrošināt uintptr_t kā daļa no stdint.h

Atzīmējot vienā no šiem veidiem, ir skaidrs, ka rādītājs abstraktā veidā norāda uz atmiņas vietu, nevis uz kādu nenoteiktu objekta tipu. Tas ir divtik svarīgi, ja veicat rādītāju matemātiku. Aruintptr_t * un tamlīdzīgi, uz kuriem norādīts izmēra elements un kā tas tiks izmantots, ir nepārprotami. Ar spēkā neesošs *, ne tik daudz.

Izvairīšanās no bieži sastopamām C kļūdām - 5 padomi

Kā izvairīties no šīm pārāk bieži pieļautajām kļūdām, strādājot ar atmiņu, masīviem un rādītājiem C? Paturiet prātā šos piecus padomus.

Strukturējiet C programmas tā, lai atmiņas īpašumtiesības nebūtu skaidras

Ja jūs tikko sākat lietotni C, ir vērts padomāt par to, kā atmiņa tiek piešķirta un atbrīvota kā viens no programmas organizatoriskajiem principiem. Ja nav skaidrs, kur vai kādos apstākļos ir atbrīvota dotā atmiņas piešķiršana, jūs lūdzat problēmas. Pielieciet papildu pūles, lai atmiņas īpašumtiesības būtu pēc iespējas skaidrākas. Jūs darīsit sev (un nākamajiem izstrādātājiem) labvēlību.

Šī ir tādu valodu filozofija kā Rust. Rūsas dēļ nav iespējams rakstīt programmu, kas pareizi apkopo, ja vien skaidri nepārprotat, kā atmiņa pieder un tiek nodota. C nav šādu ierobežojumu, taču ir saprātīgi pieņemt šo filozofiju kā vadošo gaismu, kad vien iespējams.

Izmantojiet C kompilatora opcijas, kas pasargā no atmiņas problēmām

Daudzas no šī raksta pirmajā pusē aprakstītajām problēmām var atzīmēt, izmantojot stingras kompilatora opcijas. Jaunākie izdevumi gcc, piemēram, nodrošiniet tādus rīkus kā AddressSanitizer (“ASAN”) kā kompilēšanas opciju, lai pārbaudītu, vai nav kļūdu atmiņas pārvaldībā.

Brīdinu, ka šie rīki neaizrauj pilnīgi visu. Tie ir aizsargstieņi; viņi neķer stūri, ja dodaties bezceļa apstākļos. Arī daži no šiem rīkiem, piemēram, ASAN, uzliek kompilēšanas un izpildlaika izmaksas, tāpēc jāizvairās no izlaišanas veidotājiem.

Izmantojiet Cppcheck vai Valgrind, lai analizētu C kodu atmiņas noplūdēm

Vietās, kur kompilatori paši nepietiek, tiek izmantoti citi rīki, lai aizpildītu plaisu - it īpaši, ja nepieciešams analizēt programmas uzvedību izpildlaikā.

Cppcheck veic statisko analīzi C avota kodā, lai meklētu biežākās kļūdas atmiņas pārvaldībā un nedefinētu uzvedību (cita starpā).

Valgrind nodrošina rīku kešatmiņu, lai noteiktu atmiņas un pavedienu kļūdas, darbinot C programmas. Tas ir daudz jaudīgāk nekā kompilēšanas laika analīzes izmantošana, jo jūs varat iegūt informāciju par programmas uzvedību, kad tā faktiski darbojas. Negatīvie ir tas, ka programma darbojas ar daļu no parastā ātruma. Bet tas parasti ir piemērots testēšanai.

Šie rīki nav sudraba lodes, un tie visu nenoķers. Bet tie darbojas kā daļa no vispārējas aizsardzības stratēģijas pret atmiņas nepareizu pārvaldīšanu C.

Automatizējiet C atmiņas pārvaldību, izmantojot atkritumu savācēju

Tā kā atmiņas kļūdas ir acīmredzams C problēmu avots, šeit ir viens vienkāršs risinājums: nepārvaldiet C atmiņu manuāli. Izmantojiet atkritumu savācēju.

Jā, tas ir iespējams C. Varat izmantot kaut ko līdzīgu atkritumu savācējam Boehm-Demers-Weiser, lai pievienotu automātisko atmiņas pārvaldību C programmām. Dažām programmām Boehm kolektora izmantošana var pat paātrināt situāciju. To var izmantot pat kā noplūdes noteikšanas mehānismu.

Galvenais atkritumu savācēja Boehm trūkums ir tas, ka tas nevar skenēt vai atbrīvot atmiņu, kas izmanto noklusējumu malloc. Tas izmanto savu piešķiršanas funkciju, un tas darbojas tikai uz atmiņu, kuru piešķirat tieši tai.

Nelietojiet C, ja to izdarīs cita valoda

Daži cilvēki raksta C, jo viņiem tas patiesi patīk un šķiet auglīgi. Tomēr kopumā vislabāk ir lietot C tikai tad, kad jums tas ir nepieciešams, un tad tikai nedaudz, dažās situācijās, kad tā patiešām ir ideāla izvēle.

Ja jums ir projekts, kurā izpildes veiktspēju galvenokārt ierobežos I / O vai piekļuve diskam, tad, rakstot to C, tas, visticamāk, nepadarīs to ātrāku attiecīgajos veidos un, iespējams, tikai padarīs to vairāk pakļautu kļūdām un grūti uzturēt. To pašu programmu varētu uzrakstīt Go vai Python.

Cita pieeja ir izmantot C tikai patiesi intensīvam darbam daļas un uzticamāku, lai arī lēnāku valodu citām daļām. Atkal Python var izmantot, lai iesaiņotu C bibliotēkas vai pielāgotu C kodu, padarot to par labu katlu vairāku komponentu, piemēram, komandrindas opciju apstrādes, izvēlei.

$config[zx-auto] not found$config[zx-overlay] not found