Programiranje

4 pogoste napake pri programiranju C - in 5 nasvetov, kako se jim izogniti

Le redki programski jeziki se lahko ujemajo s C glede na hitrost in moč stroja. Ta trditev je veljala pred 50 leti in velja še danes. Vendar pa obstaja razlog, da so programerji skovali izraz "footgun", da bi opisali C-jevo moč. Če niste previdni, vam lahko C odpihne prste na nogah - ali pa komu drugemu.

Tu so štiri najpogostejše napake, ki jih lahko naredite s C, in pet korakov, da jih preprečite.

Pogosta napaka C: Ne sprostitev malloc-ed pomnilnik (ali sprostitev več kot enkrat)

To je ena največjih napak v jeziku C, med katerimi je veliko upravljanje s pomnilnikom. Dodeljen pomnilnik (izvedeno z malloc funkcija) ni samodejno odstranjena v C. Naloga programerja je, da ta pomnilnik razpolaga, ko ga ne uporabljate več. Če ne sprostite ponavljajočih se zahtev po pomnilniku, vam bo na koncu prišlo do uhajanja pomnilnika. Poskusite uporabiti območje pomnilnika, ki je že osvobojeno, in vaš program se bo zrušil - ali, kar je še huje, bo šepal in postal ranljiv za napad s tem mehanizmom.

Upoštevajte, da spomin puščanje naj opisuje samo situacije, ko je spomin domnevno biti osvobojen, vendar ni. Če program še naprej dodeljuje pomnilnik, ker je pomnilnik dejansko potreben in se uporablja za delo, je morda potrebna njegova uporaba pomnilnikaneučinkovit, vendar strogo gledano ne gre za uhajanje.

Pogosta napaka C: branje polja izven meja

Tu imamo še eno najpogostejših in najbolj nevarnih napak v C. Branje mimo konca polja lahko vrne podatke o smeti. Pisanje mimo meja polja lahko poškoduje stanje programa ali pa ga popolnoma zruši ali, kar je najhuje, postane vektor napada za zlonamerno programsko opremo.

Zakaj je torej breme preverjanja meja polja prepuščeno programerju? V uradni specifikaciji C je branje ali pisanje matrike zunaj njenih meja "nedefinirano vedenje", kar pomeni, da specifikacija nima vpliva na to, kaj naj bi se zgodilo. Prevajalniku se nad njim niti ni treba pritoževati.

C že dolgo daje prednost programerju, tudi na lastno odgovornost. Prevajalnik običajno ne ujame zunaj okvira branja ali pisanja, razen če izrecno omogočite možnosti prevajalnika, da ga zaščitite. Še več, morda je mogoče med izvajanjem prekoračiti mejo polja na način, pred katerim se ne more zaščititi niti preverjanje prevajalnika.

Pogosta napaka C: Nepreverjanje rezultatov malloc

malloc in calloc (za predhodno ničelni pomnilnik) so funkcije knjižnice C, ki iz sistema pridobijo pomnilnik, dodeljen kopici. Če ne morejo dodeliti pomnilnika, ustvarijo napako. V časih, ko so imeli računalniki sorazmerno malo pomnilnika, je obstajala velika verjetnost, da bi klic malloc morda ne bo uspešen.

Čeprav imajo danes računalniki na voljo gigabajte RAM-a, še vedno obstaja možnost malloc lahko propade, zlasti pod visokim pomnilniškim pritiskom ali pri dodeljevanju velikih plošč pomnilnika hkrati. To še posebej velja za programe C, ki najprej "dodelijo" velik blok pomnilnika iz operacijskega sistema in ga nato delijo za lastno uporabo. Če prva dodelitev ne uspe, ker je prevelika, boste morda lahko zavrnili to zavrnitev, zmanjšali dodelitev in ustrezno nastavili hevristiko uporabe pomnilnika programa. Če pa dodeljevanje pomnilnika ne bo ujeto, bo lahko celoten program na trebuhu.

Pogosta napaka C: Uporaba praznina * za splošne kazalce na spomin

Uporabapraznina * opozarjanje na spomin je stara in slaba navada. Kazalci na spomin bi morali biti vedno char *, nepodpisani znak *, aliuintptr_t *. Sodobni zbirki prevajalnikov C. uintptr_t kot del stdint.h

Ko je označen na enega od teh načinov, je jasno, da se kazalnik sklicuje na pomnilniško mesto v povzetku namesto na neko nedoločeno vrsto predmeta. To je dvakrat pomembno, če izvajate matematiko kazalcev. Suintptr_t * in podobno, na katerega je usmerjen element velikosti in kako bo uporabljen, so nedvoumni. S praznina *, ne preveč.

Izogibanje pogostim napakam C - 5 nasvetov

Kako se izogniti tem preveč pogostim napakam pri delu s pomnilnikom, nizi in kazalci v jeziku C? Upoštevajte teh pet nasvetov.

Struktura programov C, tako da je lastništvo pomnilnika jasno

Če šele začenjate aplikacijo C, je vredno razmisliti o načinu dodelitve in sprostitve pomnilnika kot enega od organizacijskih načel programa. Če ni jasno, kje se določena dodelitev pomnilnika sprosti ali v kakšnih okoliščinah, sprašujete po težavah. Potrudite se, da bo lastništvo pomnilnika čim bolj jasno. Naredili boste uslugo sebi (in bodočim razvijalcem).

To je filozofija jezikov, kot je Rust. Rust onemogoča pisanje programa, ki se pravilno prevede, razen če jasno izrazite lastništvo in prenos pomnilnika. C nima takšnih omejitev, vendar je pametno to filozofijo sprejeti kot vodilno luč, kadar koli je to mogoče.

Uporabite možnosti prevajalnika C, ki varujejo pred težavami s pomnilnikom

Številne težave, opisane v prvi polovici tega članka, lahko označimo z uporabo strogih možnosti prevajalnika. Najnovejše izdaje gccna primer zagotovite orodja, kot je AddressSanitizer (“ASAN”) kot možnost kompilacije za preverjanje pred pogostimi napakami pri upravljanju pomnilnika.

Upoštevajte, ta orodja ne ujamejo popolnoma vsega. So zaščitne ograje; ne zagrabijo volana, če greste po brezpotjih. Nekatera od teh orodij, kot je ASAN, nalagajo stroške prevajanja in izvajanja, zato se jim je treba pri gradnjah različic izogibati.

Za analizo kode C zaradi puščanja pomnilnika uporabite Cppcheck ali Valgrind

Tam, kjer prevajalniki sami ne uspejo, vstopijo druga orodja, da zapolnijo vrzel - še posebej, ko gre za analizo vedenja programa med izvajanjem.

Cppcheck izvaja statično analizo izvorne kode C, da bi poiskal pogoste napake pri upravljanju s pomnilnikom in nedefiniranim vedenjem (med drugim).

Valgrind ponuja predpomnilnik orodij za odkrivanje napak v pomnilniku in nitih v zagnanih programih C. To je veliko močnejše kot pri analizi časa prevajanja, saj lahko pridobite informacije o vedenju programa, ko je dejansko v živo. Slaba stran je, da program deluje z delcem svoje običajne hitrosti. Toda to je na splošno v redu za testiranje.

Ta orodja niso srebrne krogle in ne bodo vsega ujela. Delujejo pa kot del splošne obrambne strategije pred slabim upravljanjem spomina v C.

Avtomatizirajte upravljanje pomnilnika C z zbiralnikom smeti

Ker so napake v pomnilniku očiten vir težav s sistemom C, je tu enostavna rešitev: Ne upravljajte pomnilnika v jeziku C ročno. Uporabite zbiralnik smeti.

Da, to je mogoče v C. Za zbiranje smeti Boehm-Demers-Weiser lahko uporabite nekaj, kot je zbiralnik smeti Boehm-Demers-Weiser, da programom C dodate samodejno upravljanje pomnilnika. Pri nekaterih programih lahko uporaba zbiralnika Boehm celo pospeši stvari. Uporablja se lahko celo kot mehanizem za odkrivanje puščanja.

Glavna slabost zbiralnika smeti Boehm je ta, da ne more optično prebrati ali sprostiti pomnilnika, ki uporablja privzeto malloc. Uporablja lastno funkcijo dodeljevanja in deluje samo v pomnilniku, ki ste ga dodelili posebej z njim.

Ne uporabljajte C, ko bo to storil drug jezik

Nekateri pišejo v C, ker resnično uživajo in se jim zdi plodno. Na splošno pa je najbolje, da C uporabljate le takrat, ko morate, in to le zmerno, za redke primere, ko je res idealna izbira.

Če imate projekt, pri katerem bo izvedba omejena predvsem z V / I ali dostopom do diska, pisanje v jeziku C verjetno ne bo hitrejše na najpomembnejše načine in bo verjetno le bolj nagnjeno k napakam in težko vzdrževati. Isti program bi lahko napisal v Go ali Python.

Drug pristop je uporaba C samo za resnično zmogljive deli aplikacije in bolj zanesljiv, čeprav počasnejši jezik za druge dele. Spet lahko Python uporabljamo za zavijanje knjižnic C ali C kode po meri, zaradi česar je dobra izbira za več sestavnih delov, kot je upravljanje z možnostmi ukazne vrstice.

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