Mitä tarkoittaa “ nollatarkistus ” C- tai C ++ -tekstissä?

Olen oppinut C ++: ta ja minulla on vaikeuksia ymmärtää nollaa. Erityisesti lukemissani opetusohjelmissa mainitaan ”nollatarkastus”, mutta en ole varma, mitä se tarkoittaa tai miksi se on välttämätöntä.

  • Mikä on nolla?
  • Mitä tarkoittaa ”nollan tarkistaminen”?
  • Pitäisikö minun aina tarkistaa nolla?

Koodiesimerkit olisivat erittäin arvostettuja.

Kommentit

vastaus

C- ja C ++ -kohdissa osoittimet ovat luonnostaan vaarattomia, toisin sanoen kun poiketa osoittimesta, on sinun vastuullasi varmistaa, että se osoittaa johonkin kelvolliseen; tämä on osa ”manuaalista muistinhallintaa” (toisin kuin Java-kaltaisilla kielillä toteutetut automaattiset muistinhallintamenetelmät) , PHP tai .NET-ajonaika, jonka avulla et voi luoda virheellisiä viitteitä ilman huomattavaa vaivaa).

Yleinen ratkaisu, joka tarttuu moniin virheisiin, on asettaa kaikki osoittimet, jotka eivät osoita mitään nimellä NULL (tai oikeassa muodossa C ++, 0) ja tarkistamalla se ennen osoittimen käyttöä. Erityisesti on yleistä käytäntö alustaa kaikki osoittimet NULL-arvoon (paitsi jos sinulla on jo jotain osoittamaan niitä ilmoittaessasi niitä) ja asettamaan NULL-arvoksi, kun delete tai free() heille (elleivät ne poistu heti sen jälkeen). Esimerkki (C-muodossa, mutta myös kelvollinen C ++):

void fill_foo(int* foo) { *foo = 23; // this will crash and burn if foo is NULL } 

Parempi versio:

void fill_foo(int* foo) { if (!foo) { // this is the NULL check printf("This is wrong\n"); return; } *foo = 23; } 

Ilman nollatarkistusta NULL-osoittimen välittäminen tähän toimintoon aiheuttaa erottelun, eikä mitään voi tehdä – käyttöjärjestelmä yksinkertaisesti tappaa prosessisi ja ehkä ydin-dumpin tai avaa kaatumisraportti-valintaikkunan. Kun tyhjä tarkistus on paikallaan, voit suorittaa virheen oikein ja palautua sulavasti – korjata ongelman itse, keskeyttää nykyinen toiminto, kirjoittaa lokimerkinnän, ilmoittaa käyttäjälle, mikä on tarkoituksenmukaista.

Kommentit

  • @MrLister mitä tarkoitat, tyhjät tarkastukset eivät toimi ’ eivät toimi C ++: ssa? Sinun on vain alustettava osoitin nollaan, kun ilmoitat sen.
  • Tarkoitan, että sinun on muistettava asettaa osoittimen arvoksi NULL tai se voitti ’ t työtä. Ja jos muistat, toisin sanoen, jos tiedät että osoitin on NULL, et voittanut ’ sinun tarvitse silti kutsua fill_foo. fill_foo tarkistaa, onko osoittimella arvo, ei jos osoittimella on kelvollinen -arvo. C ++: ssa osoitinten ei voida taata olevan NULL, joilla on kelvollinen arvo.
  • Väite () olisi tässä parempi ratkaisu. ’ ei ole mitään järkeä yrittää ” olla turvassa ”. Jos NULL siirrettiin sisään, se ’ on ilmeisesti väärä, joten miksi ei vain kaatua nimenomaisesti saadaksesi ohjelmoijan täysin tietoiseksi? (Ja tuotannossa sillä ei ole ’ väliä, koska olet ’ ve todistanut , että kukaan ei soita fill_foo () NULL: lla, eikö? Todellakaan, se ei ole niin vaikeaa.)
  • Älä unohda ’ unohda mainita, että vielä paremman version toiminnosta tulisi käyttää viitteitä osoittimien sijaan, jolloin NULL-tarkistus on vanhentunut.
  • Manuaalinen muistinhallinta ei tarkoita tätä, ja myös hallittu ohjelma räjähtää, ( tai nosta ainakin poikkeus, aivan kuten natiiviohjelma useimmilla kielillä), jos yrität tehdä tyhjäksi viittauksen.

Vastaa

Muut vastaukset kattivat melkein tarkan kysymyksesi. Nullatarkistus tehdään varmistaaksemme, että saamasi osoitin osoittaa oikean tyyppisen ilmentymän (esineet, primitiivit jne.).

Aion lisätä tähän oman neuvoni, Vältä nollatarkastuksia. 🙂 Nullitarkistukset (ja muut puolustavan ohjelmoinnin muodot) sekoittavat koodin ja tekevät siitä virhealtista paremmin kuin muut virheenkäsittelytekniikat.

Suosikkitekniikkani objektiosoitinten on käytettävä Null Object -mallia . Tämä tarkoittaa (osoittimen – tai vielä parempi, viittaus) tyhjään ryhmään tai luetteloon palauttamista nollan sijaan, tai palauttamalla tyhjän merkkijonon (””) nollan sijaan tai jopa merkkijonon ”0” (tai jotain vastaavaa ”ei mitään” -kohdassa), jossa oletat, että se jäsennetään kokonaislukuksi.

Bonuksena tässä on pieni asia, jota et ehkä tiennyt nollaosoittimesta, jonka CAR Hoare toteutti (ensin muodollisesti) Algol W -kielelle vuonna 1965.

Kutsun sitä miljardin dollarin virheeksi. Se oli null-viitteen keksintö vuonna 1965. Suunnittelin tuolloin ensimmäisen kattavan tyyppistä järjestelmää objektin viitteille suuntautunut kieli (ALGOL W). Tavoitteenani oli varmistaa, että kaiken viitteiden käytön tulee olla täysin turvallista ja kääntäjä suorittaa tarkistuksen automaattisesti. Mutta en voinut vastustaa kiusausta laittaa tyhjä viite yksinkertaisesti siksi, että se oli niin helppo toteuttaa. Tämä on johtanut lukemattomiin virheisiin, haavoittuvuuksiin ja järjestelmän kaatumisiin, jotka ovat todennäköisesti aiheuttaneet miljardin dollarin tuskaa ja vahinkoa viimeisen 40 vuoden aikana.

Kommentit

  • Null-objekti on jopa pahempi kuin vain nollaosoittimen käyttäminen. Jos algoritmi X vaatii tietoja Y, joita sinulla ei ole, se on ohjelmavirhe , jonka piilotat yksinkertaisesti teeskentelemällä, että teet niin.
  • Se riippuu konteksti ja jompikumpi tapa testata ” datan läsnäoloa ” voittaa testin tyhjäksi kirjaani. Kokemukseni mukaan, jos algoritmi toimii esimerkiksi luettelossa ja luettelo on tyhjä, niin algoritmilla ei yksinkertaisesti ole mitään tekemistä, ja se saavutetaan vain käyttämällä tavallisia ohjauslausekkeita, kuten for / foreach.
  • Jos algoritmilla ei ole mitään tekemistä, miksi sitä edes kutsutaan? Ja syy, miksi olet halunnut kutsua sitä ensin, on koska se tekee jotain tärkeää .
  • @DeadMG Koska ohjelmat koskevat syötettä, ja tosielämässä, toisin kuin kotitehtävät, syötöllä voi olla merkitystä (esim. tyhjä). Koodia kutsutaan edelleen kumpaankin suuntaan. Sinulla on kaksi vaihtoehtoa: joko tarkistat osuvuuden (tai tyhjyyden) tai suunnittelet algoritmit niin, että ne lukevat ja toimivat hyvin tarkistamatta nimenomaisesti asiaankuuluvuutta ehdollisten lausekkeiden avulla.
  • Tulin tänne tekemään melkein sama kommentti, joten annoin sinulle ääneni sen sijaan. Lisään kuitenkin, että tämä edustaa suurempaa ongelmaa zombie-esineistä – milloin tahansa sinulla on monivaiheisia alustuksia (tai tuhoja) sisältäviä esineitä, jotka eivät ole täysin eläviä mutta eivät aivan kuolleita. Kun näet ” turvallisen ” -koodin kielillä ilman determinististä viimeistelyä, joka on lisännyt jokaisessa funktiossa tarkistuksia objektin hävittämiseksi, se on tämä yleinen ongelma kasvatettaessa sitä ’ päätä. Sinun ei pitäisi koskaan, jos-null, sinun tulisi työskennellä valtioiden kanssa, joilla on eliniänsä tarvitsemiaan esineitä.

Vastaa

Nollaosoittimen arvo edustaa hyvin määriteltyä ”missään”; se on virheellinen osoitinarvo, jonka taataan vertailevan eriarvoisuutta muihin osoitinarvoihin. Nollaosoittimen poikkeaminen yrityksestä johtaa määrittelemättömään käyttäytymiseen ja johtaa yleensä ajonaikaisiin virheisiin, joten haluat varmistaa, että osoitin ei ole NULL, ennen kuin yrität tehdä siitä eron. Useat C- ja C ++ -kirjastotoiminnot palauttavat nollaosoittimen osoittamaan virhetilanteen. Esimerkiksi kirjastofunktio malloc palauttaa nollaosoittimen arvon, jos se ei pysty varaamaan pyydettyjen tavujen määrää, ja yrittää käyttää muistia kyseisen osoittimen kautta johtaa (yleensä) ajonaikaiselle virheelle:

int *p = malloc(sizeof *p * N); p[0] = ...; // this will (usually) blow up if malloc returned NULL 

Joten meidän on varmistettava, että malloc -puhelu onnistui tarkistamalla p vastaan NULL:

int *p = malloc(sizeof *p * N); if (p != NULL) // or just if (p) p[0] = ...; 

Odota nyt sukkaasi hetken, tämä saa vähän kuoppainen.

On olemassa nullosoittimen arvo ja nollaosoitin vakio , ja nämä kaksi eivät välttämättä ole samat. Nollaosoittimen arvo on mikä tahansa arvo, jota alla oleva arkkitehtuuri edustaa ”ei missään”. Tämä arvo voi olla 0x00000000, 0xFFFFFFFF tai 0xDEADBEEF tai jotain täysin erilaista. Älä oleta, että nollaosoittimen arvo on aina 0.

Nollaosoittimen vakio , OTOH, on aina 0-arvoinen integraalilauseke. Mitä tulee lähdekoodiin , 0 (tai mikä tahansa integraalilauseke, joka arvioi arvon 0) edustaa nollaosoitinta. Sekä C että C ++ määrittelevät NULL-makron nollaosoittimen vakiona. Kun koodisi on koottu, nollaosoitin vakio korvataan luotavalla konekoodilla sopivalla nollaosoittimen arvolla .

Huomaa myös, että NULL on vain yksi monista mahdollisista virheellisistä osoitinarvoista; jos ilmoitat automaattisen osoittimen muuttujan alustamatta sitä nimenomaisesti, kuten

int *p; 

muuttujaan alun perin tallennettu arvo on määrittelemätön , ja se ei välttämättä vastaa kelvollista tai käytettävissä olevaa muistiosoitetta. Valitettavasti ei ole (kannettavaa) tapaa kertoa, onko muu kuin NULL-osoitinarvo voimassa vai ei, ennen kuin yrität käyttää sitä. Joten jos käsittelet osoittimia, on yleensä hyvä alustaa ne nimenomaisesti NULL, kun ilmoitat heille, ja asettaa heille NULL, kun he eivät osoita aktiivisesti mitään.

Huomaa, että tämä on enemmän ongelma C: ssä kuin C ++: ssa; idiomaattisen C ++: n ei pitäisi käyttää osoittimia niin paljon.

Vastaa

On olemassa pari tapaa, jotka kaikki tekevät olennaisesti saman asia.

 int *foo = NULL; //sometimes set to 0x00 or 0 or 0L instead of NULL 

tyhjä tarkistus (tarkista onko osoitin tyhjä), versio A

 if( foo == NULL) 

tyhjä tarkistus, versio B

 if( !foo ) //since NULL is defined as 0, !foo will return a value from a null pointer 

tyhjä tarkistus, versio C

 if( foo == 0 ) 

Käytän mieluummin ensimmäistä tarkistusta, koska se kertoo tuleville kehittäjille nimenomaisesti, mitä yritit tarkistaa JA se tekee selväksi, että odotit foo: n olevan osoitin.

Vastaa

Et. Ainoa syy käyttää osoitinta C ++: ssa johtuu siitä, että haluat nimenomaisesti nollan osoittimien läsnäolon; muuten voit ottaa viitteen, joka on sekä semanttisesti helpompi käyttää että takaa ei-nollan.

Kommentit

  • @James: ’ uusi ’ ydintilassa?
  • @James: C ++: n toteutus, joka edustaa ominaisuuksia, joita merkittävä enemmistö C ++: sta koodaajat nauttivat. Tämä sisältää kaikki C ++ 03 -kieliominaisuudet (paitsi export) ja kaikki C ++ 03 -kirjaston ominaisuudet ja TR1 ja hyvä osa C ++ 11: stä.
  • Haluan toivon, etteivät ihmiset sanoisi ’ sanoisi ” -viitteet takaavat ei-nollan. ” Ne eivät ’ t. Nollaviitteen luominen on yhtä helppoa kuin nollaosoittimen, ja ne etenevät samalla tavalla.
  • @Stargazer: Kysymys on 100% tarpeeton, kun käytät työkaluja vain kielisuunnittelijoiden tapaan käytännössä ehdottaa, että sinun pitäisi.
  • @DeadMG, sillä ei ole ’ väliä onko se tarpeeton. et ’ vastannut kysymykseen .

sanon sen uudelleen: -1.

Vastaa

Jos et tarkista NULL-arvoa, etenkin jos se on osoitus strukturille, olet saattanut kohdata tietoturva-aukkojen – NULL-osoittimen poikkeama. kilpailutilanne … jonka avulla hyökkääjä voi hallita tietokonettasi.

Monet ohjelmistotoimittajat, kuten Microsoft, Oracle, Adobe, Apple … julkaisevat ohjelmistopaketin korjaamaan nämä tietoturva-aukot. Mielestäni sinun pitäisi tarkista kunkin osoittimen NULL-arvo 🙂

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *