Programavimas

4 dažniausios C programavimo klaidos ir 5 patarimai, kaip jų išvengti

Keletas programavimo kalbų gali atitikti C, kad būtų užtikrintas greitis ir mašinos lygio galia. Šis teiginys buvo teisingas prieš 50 metų ir yra teisingas iki šiol. Tačiau yra priežastis, kodėl programuotojai sugalvojo terminą „šautuvas“ apibūdinti C galią. Jei nesate atsargus, C gali nupūsti jūsų pirštus ar ką nors kitą.

Čia yra keturios dažniausiai pasitaikančios klaidos, kurias galite padaryti naudodami C, ir penki veiksmai, kuriuos galite atlikti, kad jų išvengtumėte.

Dažna C klaida: neatlaisvina mallocatmintis (arba jos atlaisvinimas daugiau nei vieną kartą)

Tai yra viena iš didelių C klaidų, iš kurių daugelis susijusios su atminties valdymu. Paskirta atmintis (padaryta naudojant malloc funkcija) automatiškai neišmetama C. Tai yra programuotojo užduotis išmesti tą atmintį, kai ji nebebus naudojama. Nepavyksta atlaisvinti pakartotinių atminties užklausų ir galiausiai nutekės atmintis. Pabandykite naudoti atminties sritį, kuri jau buvo atlaisvinta, ir jūsų programa sugrius, arba, dar blogiau, šlubuos ir taps pažeidžiama atakai naudojant tą mechanizmą.

Atkreipkite dėmesį, kad atmintis nutekėjimas turėtų aprašyti tik tas situacijas, kuriose yra atmintis tariama būti išvaduotam, bet nėra. Jei programa nuolat skiria atmintį, nes atmintis iš tikrųjų reikalinga ir naudojama darbui, tai gali būti jos naudojimasneefektyvus, bet griežtai kalbant, tai nėra nuotėkis.

Dažna C klaida: masyvo skaitymas už ribų

Čia mes turime dar vieną iš labiausiai paplitusių ir pavojingų C. klaidų. Perskaičius masyvo pabaigą, gali būti grąžinti šiukšlių duomenys. Rašymas per masyvo ribas gali sugadinti programos būseną, ją visiškai sugadinti arba, blogiausia, tapti kenkėjiškų programų atakos vektoriu.

Taigi kodėl masyvo ribų tikrinimo našta paliekama programuotojui? Oficialioje C specifikacijoje masyvo skaitymas ar rašymas už jo ribų yra „neapibrėžtas elgesys“, o tai reiškia, kad specifikacija neturi jokios įtakos tam, kas turėtų įvykti. Kompiliatorius net neprivalo dėl to skųstis.

C jau seniai pasisakė už tai, kad programuotojui būtų suteikta galia net ir savo pačių rizika. Kompiliatorius paprastai neužkliūna už ribų skaitymo ar rašymo, nebent specialiai įjungiate kompiliatoriaus parinktis, kad nuo jo apsisaugotumėte. Be to, gali būti įmanoma viršyti masyvo ribą vykdymo metu taip, kad net kompiliatoriaus patikrinimas negali apsisaugoti.

Dažna C klaida: netikrinti malloc

malloc ir kalok (iš anksto nulinei atminčiai) yra C bibliotekos funkcijos, kurios iš sistemos gauna kaupui skirtą atmintį. Jei jie negali paskirstyti atminties, jie sugeneruoja klaidą. Tais laikais, kai kompiuteriai turėjo palyginti mažai atminties, buvo nemaža galimybė skambinti malloc gali nesisekti.

Nors šiandien kompiuteriuose yra gigabaitų operatyviosios atminties, vis tiek yra galimybė malloc gali nepavykti, ypač esant dideliam atminties slėgiui arba paskirstant dideles atminties plokštes vienu metu. Tai ypač pasakytina apie C programas, kurios pirmiausia „paskirsto“ didelę atminties bloką iš OS, o paskui padalija savo reikmėms. Jei tas pirmasis paskirstymas nepavyksta, nes jis per didelis, galite sugebėti sulaikyti tą atsisakymą, sumažinti paskirstymą ir atitinkamai sureguliuoti programos atminties naudojimo euristiką. Bet jei atminties paskirstymas nepavyksta įstrigti, visa programa gali būti pilvo dalis.

Dažna C klaida: naudojant tuštuma* bendriems patarimams į atmintį

Naudojanttuštuma* atkreipti dėmesį į atmintį yra senas įprotis - ir blogas. Visada turėtų būti rodomos atminties nuorodos char *, nepasirašyta simbolis *arbauintptr_t *. Šiuolaikiniai C kompiliatorių rinkiniai turėtų pateikti uintptr_t Dalis stdint.h

Pažymėjus vienu iš šių būdų, akivaizdu, kad žymeklis abstrakčiai nurodo atminties vietą, o ne kokį nors neapibrėžtą objekto tipą. Tai dvigubai svarbu, jei atliekate rodyklių matematiką. Suuintptr_t * ir panašūs dalykai, į kuriuos nurodomas dydžio elementas ir kaip jis bus naudojamas, yra nedviprasmiški. Su tuštuma*, ne tiek ir daug.

Venkite dažniausiai pasitaikančių C klaidų - 5 patarimai

Kaip išvengti šių dažnai pasitaikančių klaidų dirbant su atmintimi, masyvais ir žymikliais C? Turėkite omenyje šiuos penkis patarimus.

Struktūrizuokite C programas taip, kad atminties nuosavybė nebūtų aiški

Jei tik pradedate „C“ programą, verta pagalvoti apie tai, kaip atmintis paskirstoma ir atlaisvinama kaip vienas iš organizacinių programos principų. Jei neaišku, kur ar kokiomis aplinkybėmis atlaisvinamas tam tikras atminties paskirstymas, prašote problemų. Darykite papildomų pastangų, kad atminties nuosavybė būtų kuo aiškesnė. Padarysi sau (ir būsimiems kūrėjams) paslaugą.

Tai yra tokių kalbų kaip Rust filosofija. Dėl rūdžių neįmanoma rašyti tinkamai kompiliuojančios programos, nebent aiškiai išreiškiate, kaip priklauso ir perduodama atmintis. C neturi tokių apribojimų, tačiau protinga tą filosofiją priimti kaip orientacinę šviesą, kai tik įmanoma.

Naudokite C kompiliatoriaus parinktis, apsaugančias nuo atminties problemų

Daugelį šio straipsnio pirmoje pusėje aprašytų problemų galima pažymėti naudojant griežtas kompiliatoriaus parinktis. Naujausi leidimai gcc, pavyzdžiui, pateikite tokius įrankius kaip „AddressSanitizer“ („ASAN“) kaip kompiliavimo parinktį, kad patikrintumėte, ar nėra klaidų, susijusių su atminties valdymu.

Įspėjame, kad šios priemonės nesuvokia absoliučiai visko. Jie yra apsauginiai turėklai; jie negriebia vairo, jei eini bekele. Be to, kai kurie iš šių įrankių, pavyzdžiui, ASAN, nustato kompiliavimo ir vykdymo išlaidas, todėl jų reikėtų vengti kuriant leidimus.

Naudokite „Cppcheck“ arba „Valgrind“, kad išanalizuotumėte C kodą dėl atminties nutekėjimo

Kai patys kompiliatoriai nesiekia, spragoms užpildyti naudojami kiti įrankiai, ypač kai reikia analizuoti programos elgseną vykdymo metu.

„Cppcheck“ atlieka statinę C šaltinio kodo analizę, kad ieškotų dažniausiai pasitaikančių atminties valdymo klaidų ir neapibrėžto elgesio (be kita ko).

„Valgrind“ pateikia įrankių talpyklą, skirtą aptikti atminties ir gijų klaidas vykdant C programas. Tai yra kur kas galingiau nei naudojant kompiliavimo laiko analizę, nes galite gauti informacijos apie programos elgesį, kai ji iš tikrųjų veikia. Neigiama yra tai, kad programa veikia savo įprasto greičio dalimi. Bet tai paprastai tinka bandymams.

Šie įrankiai nėra sidabrinės kulkos ir jie ne viską suspės. Bet jie veikia kaip bendrosios gynybos strategijos, nukreiptos prieš netinkamą atminties valdymą, dalis.

Automatizuokite C atminties valdymą naudodami šiukšlių surinkėją

Kadangi atminties klaidos yra akivaizdus C problemų šaltinis, štai vienas paprastas sprendimas: netvarkykite C atminties rankiniu būdu. Naudokitės šiukšlių surinkėju.

Taip, tai įmanoma C. Jei norite pridėti automatinį atminties valdymą prie C programų, galite naudoti kažką panašaus į „Boehm-Demers-Weiser“ šiukšlių surinkėją. Kai kurioms programoms naudojant „Boehm“ kolektorių, viskas gali netgi paspartėti. Jis netgi gali būti naudojamas kaip nuotėkio aptikimo mechanizmas.

Pagrindinis „Boehm“ šiukšlių surinkėjo trūkumas yra tas, kad jis negali nuskaityti ar atlaisvinti atminties, naudojančios numatytąjį malloc. Jis naudoja savo paskirstymo funkciją ir veikia tik atmintyje, kurią skiriate specialiai jai.

Nenaudokite C, kai tai darys kita kalba

Kai kurie žmonės rašo C, nes jiems nuoširdžiai patinka ir atrodo vaisinga. Vis dėlto geriausia naudoti C tik tada, kai privalote, o tada tik nedaug, toms kelioms situacijoms, kai tai tikrai yra idealus pasirinkimas.

Jei turite projektą, kurio vykdymo našumą daugiausia varžys įvesties / išvesties ar disko prieiga, parašius jį C, greičiausiai jis nebus greitesnis svarbiais būdais ir greičiausiai tik padarys jį labiau linkusį į klaidas ir jį bus sunku atlikti išlaikyti. Ta pati programa gali būti parašyta „Go“ arba „Python“.

Kitas būdas yra naudoti C tik už tikrai intensyvų pasirodymą dalys programos ir patikimesnė, nors ir lėtesnė kitų dalių kalba. Vėlgi, „Python“ gali būti naudojamas suvynioti C bibliotekas ar pasirinktinį C kodą, todėl tai yra geras pasirinkimas daugiau katilinės komponentų, tokių kaip komandinės eilutės parinkčių tvarkymas.