Spausdinti malloc rezultatą?

Šiame klausime kažkas pasiūlė komentuoti, kad neturėčiau įvesti malloc rezultato, t.y.

 int *sieve = malloc(sizeof(int) * length); 

ir ne:

 int *sieve = (int *) malloc(sizeof(int) * length); 

Kodėl taip yra?

2149
03 марта '09 в 13:13 2009-03-03 13:13 Patrick McDonald paprašė kovo 03'09, 13:13 2009-03-03 13:13
@ 28 atsakymai

Ne ; Jūs nesuteikiate rezultatų, nes:

  • Tai neprivaloma, nes void * automatiškai ir saugiai pereina į bet kurį kitą tipą.
  • Jis sukelia sumaištį kodui, o liejimas nėra labai lengva skaityti (ypač jei rodyklės tipas yra ilgas).
  • Tai leidžia jums kartoti, kas paprastai yra bloga.
  • Jis gali paslėpti klaidą, jei pamiršote įtraukti <stdlib.h> . Tai gali sukelti gedimus (arba dar blogiau, dėl to, kad kai kuriose visiškai skirtingose ​​kodo dalyse avarijos baigsis vėliau). Pagalvokite, kas atsitiks, jei rodyklės ir sveikieji skaičiai yra skirtingi; tada jūs paslėpsite įspėjimą, kai jūs gausite, ir jūs galite prarasti šiek tiek grąžinto adreso. Pastaba: su C11 netiesioginės funkcijos išnyko iš C, ir šis taškas nebėra aktualus, nes nėra automatinės prielaidos, kad nedeklaruotos funkcijos grąžina int .

Kaip paaiškinimą, atkreipkite dėmesį, kad aš pasakiau: „Negalite mesti“, o ne „nereikia nutraukti“. Mano nuomone, tai yra nesugebėjimas įjungti minties, net jei jums tai teisinga. Nėra jokių privalumų, tačiau daugybė galimų pavojų, įskaitant įtraukimą, rodo, kad jūs nežinote apie riziką.

Taip pat atkreipkite dėmesį, kaip pažymėjo komentatoriai, kad minėti pokalbiai apie tiesioginį C, o ne C ++. Labai tikiu, kad C ir C ++ yra atskiros kalbos.

Jei norite pridėti daugiau, jūsų kodas be reikalo pakartoja tipo ( int ) informaciją, kuri gali sukelti klaidų. Geriau nukreipti rodyklę, naudojamą grąžinimo vertei išsaugoti, kad „blokuotumėte“ du:

 int *sieve = malloc(length * sizeof *sieve); 

Jis taip pat atneša length į priekį, kad padidintų matomumą ir sumažintų papildomų skliaustų su sizeof ; jie reikalingi tik tada, kai argumentas yra tipo pavadinimas. Atrodo, kad daugelis žmonių tai nežino (arba ignoruoja), todėl jų kodas yra išsamesnis. Atminkite: sizeof nėra funkcija! :)


Kai judate length į priekį, kai kuriais retais atvejais matomumas gali padidėti, taip pat turėtumėte atkreipti dėmesį į tai, kad apskritai geriau parašyti tokią išraišką kaip:

 int *sieve = malloc(sizeof *sieve * length); 

Nuo tada, kai iš pradžių laikote nuspaudę dydį, šiuo atveju dauginimas atliekamas bent size_t .

Palyginti: malloc(sizeof *sieve * length * width) vs malloc(length * width * sizeof *sieve) gali perpildyti length * width , kai width ir length yra mažesni nei size_t .

2003 m
03 марта '09 в 13:17 2009-03-03 13:17 atsakymas atsipalaiduoja kovo 03 '09, 13:17 2009-03-03 13:17

„C“ nereikia nurodyti „ malloc grąžinimo vertės. Rodyklė, nukreipta į tuštumą, kurį grąžina malloc , automatiškai konvertuojama į teisingą tipą. Tačiau, jei norite, kad jūsų kodas būtų sukompiliuotas naudojant „C ++“ kompiliatorių, turite atlikti „cast“. Pageidautina alternatyva bendruomenei yra:

 int *sieve = malloc(sizeof *sieve * length); 

kuri papildomai atlaisvina jus nuo nerimauti keičiant dešinę raiškos pusę, jei pakeisite sieve tipą.

Pilys yra blogos, kaip nurodė žmonės. Specialiai uždengtas žymeklis.

338
03 марта '09 в 13:17 2009-03-03 13:17 atsakymas pateikiamas dirkgently kovo 03'09 , 13:17 2009-03-03 13:17

Jūs darote, nes:

  • Tai daro jūsų kodą daugiau nešiojamų tarp C ir C ++, o kaip SO patirtis rodo, daugelis programuotojų teigia, kad jie rašo C, kai rašo C ++ (arba vietinio C kompiliatoriaus plius plėtiniai).
  • Jei to nepadarysite, galite paslėpti klaidą : pastebėkite visus SO-obfuscation pavyzdžius, kai rašote type * ir type ** .
  • Idėja, kad ji neleidžia pastebėti, kad negalite #include atitinkamą antraštės failą, praleidžia medžius miškams . Tai tas pats, kaip sakydamas: „Nesijaudinkite dėl to, kad neprašėte kompiliatoriaus skųstis, kad nematote prototipų - tai erzina stdlib.h yra svarbus dalykas, kurį reikia prisiminti!“.
  • Tai skatina papildomą kognityvinį kryžminį patvirtinimą . Jis nurodo (apskaičiuotą) norimą tipą šalia aritmetinio, kurį atliekate šio kintamojo neapdorotam dydžiui. Tikiuosi, kad galite atlikti SO tyrimą, kuris rodo, kad malloc() klaidos yra sugautos daug greičiau, kai yra ritinys. Kaip ir teiginiai, anotacijos, rodančios ketinimą sumažinti klaidų skaičių.
  • Pakartokite save taip, kad mašina galėtų išbandyti, dažnai yra didelė idėja. Tiesą sakant, koks yra pareiškimas, ir toks dalyvių naudojimas yra pareiškimas. Pareiškimai vis dar yra labiausiai paplitęs būdas, kuriuo mes turime teisingą kodą, nes Turingas šią idėją sukūrė prieš daugelį metų.
306
14 февр. Ron Burko atsakymas 14 vasaris 2013-02-14 19:15 '13, 19:15, 2013-02-14 19:15

Kaip nurodyta, tai nėra reikalinga C, bet C ++. Jei manote, kad ketinate surinkti savo C kodą naudodami C ++ kompiliatorių, dėl kokių nors priežasčių galite naudoti makrokomandą, pavyzdžiui:

 #ifdef __cplusplus # define NEW(type, count) ((type *)calloc(count, sizeof(type))) #else # define NEW(type, count) (calloc(count, sizeof(type))) #endif 

Taigi jūs vis tiek galite rašyti jį labai kompaktiškai:

 int *sieve = NEW(int, 1); 

ir jis bus sukompiliuotas C ir C ++.

155
03 марта '09 в 14:17 2009-03-03 14:17 quinminų atsakymas kovo 03'09 , 14:17 2009-03-03 14:17

wikipedia

Liejimo privalumai

  • Įtraukus vaidmenį, C programa arba funkcija gali sudaryti kaip C ++.

  • Įrašymas leidžia Malloc versijas iki 1989 m., Iš pradžių grąžintas char *.

  • Liejimas gali padėti kūrėjui nustatyti neatitikimus tipe, jei pasikeičia paskirties rodyklės tipas, ypač jei rodiklis yra paskelbtas toli nuo malloc () skambučio (nors šiuolaikiniai kompiliatoriai ir statiniai analizatoriai gali įspėti apie šį elgesį be liejimo).

Liejimo trūkumai

  • ANSI C standarte liejimas yra nereikalingas.

  • Įtraukus vaidmenį, gali būti užmaskuotas stdlib.h antraštės, kurioje rastas malloc prototipas, įtraukimo nepakankamumas. Nesant malloc prototipo, standartas reikalauja, kad C kompiliatorius prisiimtų, kad malloc grąžina int. Jei nėra ritinio, perspėjamas, kai rodyklė priskiriama tam sveikam skaičiui; vis dėlto šis metimas neparodomas, paslėpdamas klaidą. Tam tikrose architektūrose ir duomenų modeliuose (pvz., 64 bitų sistemose LP64, kur yra ilgos ir 64 bitų rodyklės, ir 32 bitų int), ši klaida iš tikrųjų gali sukelti neapibrėžtą elgesį, nes netiesiogiai deklaruotas malloc grąžina 32 bitų vertę, kadangi faktiškai apibrėžta funkcija grąžina 64 bitų vertę. Priklausomai nuo skambučių konvencijų ir išdėstymo atminties, tai gali lemti kamino pertrauką. Šis klausimas greičiausiai nepastebės šiuolaikiniuose kompiliatoriuose, nes jie tolygiai pateikia įspėjimus, kad buvo naudojama nedeklaruota funkcija, todėl įspėjimai vis tiek bus rodomi. Pvz., Numatytasis GCC elgesys yra įspėjimas, rodantis „nesuderinama netiesioginė integruotos funkcijos deklaracija“, neatsižvelgiant į tai, ar jis yra, ar ne.

  • Jei žymeklio tipas pasikeičia, kai jis yra paskelbtas, taip pat galite keisti visas eilutes, kuriose yra vadinamas malloc ir vykdomas.

Nors pageidaujamas būdas yra ne „casting malloc“, o dauguma patyrusių programuotojų pasirenka jį , turėtumėte naudoti tai, ką norite sužinoti apie problemas.

ty: Jei reikia surinkti C programą, pvz., C ++ (nors tai yra atskira kalba), turite naudoti malloc su liejimu.

107
10 окт. atsakymas pateikiamas ashiquzzaman33 10 oct. 2015-10-10 00:23 '15 prie 0:23 2015-10-10 00:23

„C“ galite netiesiogiai konvertuoti tuščią rodyklę į bet kurį kitą rodiklį, taigi liejimas nereikalingas. Naudodami vieną, galite pasiūlyti atsitiktiniam stebėtojui, kad yra kokių nors priežasčių, dėl kurių reikia, kas gali būti klaidinanti.

96
03 марта '09 в 13:18 2009-03-03 13:18 atsakymą pateikė PaulJWilliams kovo 03 '09, 13:18 2009-03-03 13:18

Jūs nenurodote „malloc“ rezultato, nes jis priduria nenaudingą kodą jūsų kodui.

Dažniausia priežastis, kodėl žmonės daro Malloc rezultatą, yra tai, kad jie nėra tikri, kaip veikia C kalba, tai yra įspėjamasis ženklas: jei nežinote, kaip veikia tam tikras kalbos mechanizmas, nedarykite prielaidų. Išbandykite jį arba paklauskite kamino perpildymo.

Kai kurie komentarai:

  • Tuščiasis žymeklis gali būti konvertuojamas į / iš bet kurio kito žymeklio tipo be aiškaus liejimo (C11 6.3.2.3 ir 6.5.16.1).

  • Tačiau „C ++“ neleidžia netiesioginio perdavimo tarp void* ir kito rodyklės tipo. Taigi, C ++, dauguma bus teisinga. Bet jei programuojate C + +, turėtumėte naudoti new , o ne malloc (). Ir jūs niekada neturėtumėte sukompiliuoti C kodo su C ++ kompilatoriumi.

    Jei reikia palaikyti tiek C, tiek C ++ su tuo pačiu šaltiniu, naudokite kompiliatorių jungiklius, kad pažymėtumėte skirtumus. Nebandykite patenkinti abiejų vietų su tuo pačiu kodu, nes jie yra nesuderinami.

  • Jei C kompiliatorius negali rasti funkcijos, nes pamiršote įtraukti antraštę, gausite kompiliatoriaus / sąsajos klaidos pranešimą. Todėl, jei pamiršote <stdlib.h> , kad nėra <stdlib.h> , negalėsite sukurti savo programos.

  • Senovės kompiliatoriuose, kurie laikosi standartinės versijos, kuri yra senesnė nei 25 metų, pamiršus įtraukti <stdlib.h> bus pavojingas elgesys. Kadangi šiame sename standarte, funkcijos, neturinčios matomo prototipo, netiesiogiai konvertuoja grąžinimo tipą į int . Išgauti iš malloc rezultato aiškiai paslėpta ši klaida.

    Bet tai tikrai nėra problema. Jūs nesinaudojate 25 metų kompiuteriu, tad kodėl turėtumėte naudoti 25 metų kompiliatorių?

87
20 марта '14 в 18:53 2014-03-20 18:53 atsakymą įteikė Lundinas kovo 20 d. 14 val. 18:53 2014-03-20 18:53

C atveju jūs gaunate netiesioginę konversiją iš void* į bet kurį kitą rodiklį (duomenis).

85
03 марта '09 в 13:16 2009-03-03 13:16 atsakymą pateikė EFraim kovo 03 '09, 13:16 2009-03-03 13:16

Dabar malloc() grąžintos vertės vertė nereikalinga, bet norėčiau pridėti vieną tašką, kuris, kaip atrodo, niekas nenurodė:

Senovėje, ty prieš ANSI C , void * kaip bendras rodyklės tipas, char * yra tokio naudojimo tipas. Tokiu atveju perteikimas gali išjungti kompiliatoriaus įspėjimus.

Nuoroda: C Dažniausiai užduodami klausimai

65
09 июня '13 в 20:31 2013-06-09 20:31 atsakymą pateikė „ Yu Hao“ birželio 13 d. 13 d. 20:31 2013-06-09 20:31

malloc rezultatų nėra būtina, nes jis grąžina void* , o void* gali nurodyti bet kokį duomenų tipą.

48
08 февр. Atsakymą pateikė user968000 08 Feb. 2013-02-08 01:22 '13 ne 1:22 2013-02-08 01:22

Tiesiog pridėdamas savo patirtį, studijuodamas kompiuterių inžineriją, matau, kad du ar trys profesoriai, kuriuos mačiau C skyriuje, visuomet nukrito malloc, bet aš paprašiau (su puikia santrauka ir supratimu apie C) man pasakė, kad tai visiškai nereikalinga , bet tik būdavo visiškai konkretūs, ir kad studentai taptų mentalitetais visiškai konkretūs. Iš esmės, liejimas nieko nekeičia, kaip jis veikia, tai daro būtent tai, ką jis sako, skiria atmintį, o liejimas jai nedaro įtakos, jūs gaunate tą pačią atmintį, ir net jei ją gaminate netinkamai ( ir kažkaip išvengti kompiliatoriaus klaidos). C taip pat nurodys.

Redaguoti: liejimas turi tam tikrą tašką. Kai naudojate masyvo žymėjimą, sukurtas kodas turi žinoti, kiek atminties reikia judėti, kad pasiektų kito elemento pradžią, tai pasiekiama liejant. Taigi jūs žinote, kad dvigubai einate 8 baitai į priekį, o jūs einate 4, ir pan. Todėl, jei naudojate žymeklio žymėjimą, jis neturi reikšmės masyvo žymėjime.

47
28 марта '14 в 21:21 2014-03-28 21:21 atsakymą pateikė vartotojo3079666 kovo 28 d. 14:21 2014-03-28 21:21

Tuščiasis žymeklis yra bendras rodiklis, o C palaiko netiesioginį konversiją iš rodyklės tipo negaliojančiu į kitus tipus, todėl nereikia to aiškiai nurodyti.

Tačiau, jei norite, kad tas pats kodas būtų visiškai suderinamas su C + + platforma, kuri nepalaiko numanomo konvertavimo, turite atlikti tipų nustatymą, todėl viskas priklauso nuo naudojimo.

28
13 июля '14 в 9:42 2014-07-13 09:42 atsakymą pateikė Endeavor liepos 14 d. 14 val. 9:42 2014-07-13 09:42

Tai yra GNU C bibliotekos informacijos vadovas:

malloc rezultatą galite išsaugoti bet kuriame rodiklio kintamajame be vertimo, nes ISO C automatiškai konvertuoja void * tipą į kitą rodyklės tipą, kai reikia. Tačiau šis vaidmuo yra būtinas kitame kontekste nei priskyrimo operatoriai, arba jei norite, kad jūsų kodas veiktų tradiciniame C.

Iš tiesų, ISO standartas C11 (p347) teigia:

Rodyklė grąžinama, jei paskirstymas yra sėkmingai įvykdytas, kad jis būtų priskirtas rodikliui bet kokio tipo objektui, turinčiam esminį lygiavimo reikalavimą, ir tada naudojamas prieiti prie tokio objekto ar tokių objektų masyvo priskirtoje erdvėje (kol erdvė yra aiškiai išlaisvinta) )

28
09 окт. atsakymas duotas Slothworks 09 okt. 2015-10-09 20:47 '15 ne 20:47 2015-10-09 20:47

Grąžinimo tipas yra negaliojantis *, kurį galima priskirti norimam dereferenciniam duomenų rodyklės tipui.

27
26 апр. atsakymas pateikiamas apsikeitimo sandoriais 26 balandžio mėn. 2013-04-26 19:43 '13, 19:43, 2013-04-26 19:43

C, void pointer gali būti priskirtas bet kuriam rodikliui, todėl neturėtumėte naudoti tokio tipo. Jei norite paryškinti „saugų tipą“, galiu rekomenduoti šias makrofunkcijas, kurias visada naudoju savo „C“ projektuose:

 #include <stdlib.h> #define NEW_ARRAY(ptr, n) (ptr) = malloc((n) * sizeof *(ptr)) #define NEW(ptr) NEW_ARRAY((ptr), 1) 

Su jais galite tiesiog pasakyti

 NEW_ARRAY(sieve, length); 

Ne dinaminėms matricoms - trečioji privaloma funkcija

 #define LEN(arr) (sizeof (arr) / sizeof (arr)[0]) 

kas daro masyvo kilpas saugesnes ir patogesnes:

 int i, a[100]; for (i = 0; i < LEN(a); i++) { ... } 
24
04 сент. atsakymą pateikė rugpjūčio Karlstrom 04 sept. 2015-09-04 14:52 '15 ne 14:52 2015-09-04 14:52

Tai priklauso nuo programavimo kalbos ir kompiliatoriaus. Jei naudojate malloc C, nereikia jo įvesti, nes jis automatiškai įves. Tačiau, jei naudojate „C ++“, turite įvesti „cast“, nes malloc grįš void* .

24
17 марта '14 в 16:16 2014-03-17 16:16 atsakymą pateikė Jeyamaran , kovo 17 d. 14, 16:16 2014-03-17 16:16

Žmonės, pripratę prie GCC ir C>

Bėgant metams baisiai išsigandau kompiliatoriai, kuriuos turėčiau naudoti. Dažnai įmonės ir vadovai priima itin konservatyvų požiūrį į kompiliatorių keitimą ir net tikrina, ar naujasis kompiliatorius bus jų sistemoje (su geresniais standartais ir kodo optimizavimu). Praktinė darbo kūrėjų realybė yra ta, kad koduodami turite padengti savo bazes, ir, deja, puikūs šoviniai yra geras įprotis, jei negalite kontroliuoti, kuris kompiliatorius gali būti pritaikytas jūsų kodui.

Taip pat norėčiau pasakyti, kad daugelis organizacijų taiko savo kodavimo standartą ir kad tai turėtų būti metodas, kuriuo vadovaujasi žmonės, jei jie yra apibrėžti. Nesant aiškių nurodymų, aš linkiu rengti visur, o ne vergišką standarto laikymąsi.

Argumentas, kad jis nėra būtinas pagal galiojančius standartus, yra gana priimtinas. Tačiau šis argumentas praleidžia realaus pasaulio praktiškumą. Mes nekoduojame pasaulyje, kurį valdo tik dienos standartas, bet praktika, kurią norėčiau vadinti „vietos valdymo sritimi“. Ir ji sulenkė ir iškreipė daugiau nei tik erdvę.

YMMV.

Aš linkęs galvoti, kad malloc yra gynybinė operacija. Ne gražus, ne tobulas, bet paprastai saugus. (Sąžiningai, jei neįtraukėte stdlib.h, turite daugiau problemų nei naudojant malloc!).

14
04 дек. Atsakymas duotas StephenG 04 Dec. 2015-12-04 20:27 '15, 08:27 pm 2015-12-04 20:27

Aš įdėjau tik tam, kad būtų parodyta, kad tipo sistemoje yra negraži skylė, o tai leidžia jums sukurti kodą, pvz., Šį fragmentą, be diagnozės, net jei jokie vertimai nenaudojami blogai konversijai sukelti:

 double d; void *p =  int *q = p; 

Apgailestauju, kad tai nebuvo (ir tai nėra C + +), todėl atsisakau. Tai mano skonis ir mano programavimo politika. Aš ne tik indeksuokite rodyklę, bet ir efektyviai išleidžiu biuletenį ir išvariu nesąmonės demonus . Jei aš negaliu iš tikrųjų išnaudoti nesąmonės , bent jau leiskite man išreikšti savo norą tai daryti su protesto gestu.

Tiesą sakant, gera praktika, kad malloc (ir draugai) būtų supakuota su funkcijomis, kurios grąžina unsigned char * , ir iš esmės niekada nenaudoja kodo void * . Jei jums reikia bendro rodyklės bet kuriam objektui, naudokite char * arba unsigned char * , ir jūs turite išmesti į abi puses. Galbūt vienintelė atsipalaidavimas, kurį galima pasmerkti, yra funkcijų, pvz., „ memset ir „ memcpy be liejimo.

Klausimo ir suderinamumo su „C ++“ klausimu, jei rašote kodą taip, kad jis būtų sudarytas kaip „C“ ir „C ++“ (šiuo atveju jums reikia nurodyti grąžos vertę malloc kai priskiriate jį kitam nei void * ), jūs jūs galite padaryti labai naudingą dalyką sau: galite naudoti liejimui skirtas makrokomandas, kurios paverčiamas kaip C + + stilių, kai jie sudaromi kaip C + +, bet redaguojami į C-rėmelį, kai jie sudaromi kaip C:

  #ifdef __cplusplus #define strip_qual(TYPE, EXPR) (const_cast<TYPE>(EXPR)) #define convert(TYPE, EXPR) (static_cast<TYPE>(EXPR)) #define coerce(TYPE, EXPR) (reinterpret_cast<TYPE>(EXPR)) #else #define strip_qual(TYPE, EXPR) ((TYPE) (EXPR)) #define convert(TYPE, EXPR) ((TYPE) (EXPR)) #define coerce(TYPE, EXPR) ((TYPE) (EXPR)) #endif 

Jei laikysitės šių makrokomandų, paprastas jūsų kodo bazės paieška šiems identifikatoriams parodys jums, kur yra visos jūsų metimai, todėl galite patikrinti, ar bet kuris iš jų yra neteisingas.

Tada, tęsdami, jei reguliariai kaupiate C ++ kodą, jis naudos atitinkamą formą. Pvz., Jei naudojate strip_qual tik pašalinti const arba volatile , bet programa keičiasi taip, kad tipo konversija vyksta dabar, gausite diagnozę, ir norėsite pasiekti norimą konversiją.