Mai mult
Am aruncat rezultatul malloc?
În această întrebare, cineva a sugerat într-un comentariu că ar trebui să nu distribuție rezultatul malloc
, adică
int *sieve = malloc(sizeof(int) * length);
mai degrabă decât:
int *sieve = (int *) malloc(sizeof(int) * length);
De ce ar fi cazul?
2305
26
Nu; ce don't distribuție rezultatul, deoarece:
void *
este în mod automat și în condiții de siguranță promovat la orice alt tip pointer în acest caz.. Acest lucru poate cauza accidente (sau, mai rău, nu ** provoca un accident până mult mai târziu în unele total diferite, o parte din cod). Ia în considerare ce se întâmplă dacă indicii și întregi sunt de dimensiuni diferite; atunci're ascunde un avertisment prin turnare și-ar putea pierde bucăți de întors adresa. Notă: ca de C99 funcțiile latente sunt plecat din C, iar acest punct nu mai este relevant, deoarece nu's nici presupunerea automată că nedeclarate funcții reveni
int`.Ca o clarificare, rețineți că am spus "nu't exprimate", nu "nu't nevoie de a arunca". În opinia mea, a's un eșec pentru a include exprimate, chiar dacă ai dreptate. Pur și simplu nu există beneficii pentru a face asta, dar o grămadă de riscuri potențiale, inclusiv exprimate indică faptul că don't știu despre riscurile.
Rețineți, de asemenea, ca comentatori subliniază, că cele de mai sus vorbește despre drept C, nu C++. Eu cred foarte ferm în C și C++ ca limbi separate.
Pentru a adăuga mai mult, codul inutil repetă tip de informații (
int
) care pot provoca erori. L's mai bine de referință indicatorul utilizat pentru a stoca valoarea de returnare, pentru "de blocare" cele două împreună:Acest lucru, de asemenea, se mută la "lungime" în față pentru o vizibilitate sporită, și picături disponibilizați paranteze cu sizeof
; ei *sunt necesare doar atunci când* * * argument este un nume de tip. Mulți oameni par să nu știe (sau ignora) acest lucru, ceea ce face codul mult mai detaliată. Amintiți-vă:
sizeof` nu este o funcție! :)În timp ce se deplasează "lungime" în față poate crește vizibilitatea în unele cazuri rare, unul ar trebui să acorde atenție, de asemenea că, în cazul general, ar trebui să fie mai bine să scrie expresia ca:
Deoarece păstrarea
sizeof
în primul rând, în acest caz, asigură multiplicarea se face cu cel puținsize_t
matematica.Compara:
malloc(sizeof *sită * lungime * latime)
vs.malloc(lungime * lățime * sizeof *sită)
cea de-a doua poate revărsa pe lungime * latime când "lățime" și "lungime" sunt mai mici tipuri desize_t
.În C, nu't nevoie pentru a arunca valoarea de returnare a
malloc
. La pointer la void returnat de malloc` este automat convertit la tipul corect. Cu toate acestea, dacă doriți codul dvs. pentru a compila cu un compilator C++, o distributie este nevoie. O alternativă de preferat în rândul comunității este de a utiliza următoarele opțiuni:care, în plus, te elibereaza de la a fi nevoie să vă faceți griji cu privire la schimbarea partea dreaptă a expresiei dacă schimbați tipul de sită`.
Mulajele sunt rele, așa cum s-a subliniat. Special indicatorul de mulaje.
Ai nu distributie, deoarece:
tip * "versus" tip **
.#include
un caz antet fișier lipsește pădurea de copaci. L's la fel cu a spune "nu't vă faceți griji despre faptul că nu a reușit să cere compilatorului să se plângă de a nu vedea prototipuri ... asta plictisitor stdlib.h este cel mai important lucru de reținut!"malloc()
bug-uri sunt prins mult mai repede atunci când există's-o aruncat. Ca cu afirmații, adnotări, care dezvăluie intenția de scădere bug-uri.Ca și alte precizat, nu este necesar pentru C, dar pentru C++. Dacă credeți că aveți de gând pentru a compila cod C cu un compilator C++, pentru care motive, puteți folosi un macro în schimb, cum ar fi:
În acest fel puteți scrie încă într-un mod foarte compact:
și acesta va compila pentru C și C++.
De Wikipedia:
Deși malloc fără de turnare este metoda preferată și de cele mai multe programatori cu experiență alege-l, ar trebui să utilizați oricare îți place să ai cunoștință de probleme.
eu.e: Dacă aveți nevoie pentru a compila program C ca C++ (Deși este o limbă separată) trebuie să arunce urmare a folosi
malloc
.În C puteți converti implicit un gol pointer la orice alt tip de pointer, deci o distributie nu este necesar. Folosind o poate sugera la observator casual că există un motiv de ce unul este necesar, care pot fi înșelătoare.
Nu't exprimate rezultatul malloc, deoarece acest lucru adaugă inutil dezordine la cod.
Cel mai frecvent motiv pentru care oamenii arunca urmare a malloc este, deoarece acestea sunt nu sunteți sigur cum limbajul C lucrări. Ca's un semn de avertizare: dacă nu't știu cum o anumită limbă mecanism funcționează, atunci nu't_ să ia o ghici. Uite-l sau pune pe Stack Overflow.
Unele comentarii:
Un gol pointer poate fi convertit la/de la orice alt tip pointer fără explicit exprimate (C11 6.3.2.3 și 6.5.16.1).
C++ va toate acestea, nu permit o implicite exprimate între
void*
și un alt tip pointer. Deci, în C++, exprimate ar fi fost corectă. Dar dacă ai un program în C++, ar trebui să folosiți " noi " și nu malloc(). Și niciodată nu ar trebui să compila cod C, folosind un compilator C++.Dacă aveți nevoie pentru a sprijini atât C și C++ cu același cod sursă, utilizați compiler switch-uri pentru a marca diferențele. Nu încercați să sătura atât în limba standarde cu același cod, deoarece acestea nu sunt compatibile.
Dacă un compilator C nu poate găsi o funcție pentru că ai uitat să includă antet, veți obține un compilator/linker error despre asta. Deci, dacă ați uitat să includ<stdlib.h> asta's nu-i nimic, ai castigat't fi capabil de a construi dvs. de program.
Pe vechi compilatoare care să urmeze o versiune a standardului, care este mai mult de 25 de ani, uitând să includă
<stdlib.h>
ar duce la un comportament periculos. Pentru că în acel vechi standard, funcțiile fără o vizibilă prototip implicit convertit tipul de returnare aint
. Turnare rezultatul de la malloc în mod explicit ar ascunde acest bug.Dar care este de fapt o non-problema. Nu't cu ajutorul a 25 de ani de calculator, deci de ce ai folosi-o 25 de ani compiler?
În C veți obține o conversie implicită de
void*
pentru orice alte (date) pointer.Turnare valoarea returnat de malloc()` nu este necesar acum, dar am'd dori să adăugați un punct care se pare că nimeni nu a subliniat:
În zilele vechi, care este, înainte de ANSI C oferă
void *
ca tip generic de indicii,char *
este de tip pentru o astfel de utilizare. În acest caz, distribuția poate închide compilatorul avertismente.Referință: C FAQ
Nu este obligatoriu să arunce rezultatele
malloc
, când se întoarcevoid*
, și `void* poate fi indicat pentru orice tip de date.Doar adăugând experiența mea, studiind ingineria calculatoarelor văd că doi sau trei profesori care l-am văzut scris în C întotdeauna exprimate malloc, cu toate acestea am cerut (cu o imensă CV-ul și înțelegerea de C) mi-a spus că este absolut inutile, dar folosit doar pentru a fi absolut specifice, și de a primi studenți în mentalitatea de a fi absolut specifice. În esență, turnare nu se va schimba ceva în modul în care aceasta funcționează, face exact ceea ce spune, alocă memorie, și turnare nu are efect, veți obține aceeași memorie, și chiar dacă ai arunca-l la altceva din greșeală (și cumva se sustrage compiler) C va accesa în același mod.
Edit: Turnare are un anumit punct. Atunci când utilizați notație matrice, codul generat trebuie să știe cât de multe locuri de memorie trebuie să avans pentru a ajunge la începutul următorului element, acest lucru este realizat prin turnare. În acest fel știi că pentru un dublu te duci 8 octeți față, în timp ce pentru un int te duci 4, și așa mai departe. Astfel, nu are nici un efect dacă utilizați indicatorul de notație, în notație matrice devine necesar.
Aceasta este ceea ce GNU C Library Referință manualul spune:
Și într-adevăr ISO C11 standard (p347) spune așa:
Un pointer void este un obiect generic pointer și C sprijină conversia implicită la un vid de tip pointer la alte tipuri, astfel încât nu este nevoie de explicit typecasting-o.
Cu toate acestea, dacă doriți același lucru cod perfect compatibil pe un C++ platforma, care nu are suport de conversie implicit, aveți nevoie pentru a face typecasting, deci, totul depinde de gradul de utilizare.
Întors tip este void*, care pot fi exprimate dorit tipul de date pointer, în scopul de a fi dereferenceable.
În limbajul C, un gol pointer pot fi atribuite la orice pointer, care este de ce tu ar trebui să nu utilizați un tip de distributie. Dacă vrei "tip în condiții de siguranță" alocarea, eu pot recomanda următoarele funcții macro, pe care am folosi întotdeauna în C proiecte:
Cu acestea, în loc puteți spune pur și simplu
Pentru non-matrice dinamice, cea de-a treia trebuie să aibă funcția macro este
ceea ce face matrice bucle mai sigur și mai convenabil:
Depinde de limbajul de programare și compilatoare. Dacă utilizați
malloc
în C nu este nevoie să tastați-l arunce, ca acesta va automat de tip cast, cu toate Acestea, dacă dumneavoastră folosind C++, atunci ar trebui să-tip cast, pentru cămalloc
va returna onul*
tip.Oamenii folosit pentru a CCG și Zăngănit sunt rasfatati. L's nu toate așa de bine acolo.
Am fost destul de îngrozit de-a lungul anilor de uluitor în vârstă de compilatoare I'am fost necesar pentru a utiliza. Adesea, companiile și managerii adopta un ultra-conservator abordare a schimba compilatoare și nici nu va test dacă un nou compilator ( cu mai bine de respectarea standardelor și optimizarea codului ) va lucra în sistemul lor. În realitatea practică de lucru pentru dezvoltatori este că atunci când te're codificare aveți nevoie pentru a acoperi bazele și, din păcate, turnare mallocs este un obicei bun, dacă nu poți controla ceea ce compiler poate fi aplicat la cod.
Aș sugera, de asemenea, că multe organizații se aplică un standard de codificare a lor și că că ar trebui să fie metoda de oameni să urmeze, dacă este definit. În absența explicită de orientare am tendința de a merge pentru cele mai susceptibile de a compila peste tot, mai degrabă decât servilă aderarea la un standard.
Argumentul pe care-l's nu este necesar sub standardele actuale este destul de valabil. Dar acest argument omite aspectele practice din lumea reală. Noi nu cod într-o lume condusă exclusiv de către standard al zilei, dar de cele practice a ceea ce îmi place să numesc "managementul local's câmp realitate". Și că's îndoit și răsucit de mai mult spațiu-timp a fost vreodată. :-)
YMMV.
Eu tind să cred că de turnare malloc ca o operație defensivă. Nu destul, nu perfect, dar, în general, în condiții de siguranță. ( Sincer, daca'nu am inclus stdlib.h atunci've cale mai multe probleme decât turnare malloc ! ).
Nu't exprimate rezultatul
malloc()
.În general, *don't fontă sau din `void `**.
Tipic pentru un motiv pentru a nu face așa este că eșecul de a
#includ <stdlib.h>
ar putea trece neobservat. Asta e't o problemă pentru o lungă perioadă de timp acum ca C99 făcut implicit funcția de declarații ilegal, deci, dacă dumneavoastră compiler este conform cu cel puțin C99, veți obține un diagnostic mesaj.Dar nu's a mult mai puternic motiv să nu introducă inutile pointer mulaje:
În C, o indicatorul de distributie este aproape întotdeauna o eroare. Acest lucru este pentru că de următoarea regulă (§6.5 p7 în N1570, cel mai recent proiect pentru C11):
Acest lucru este, de asemenea, cunoscut sub numele de stricte aliasing regula. Deci următorul cod este comportament nedefinit:
Și, uneori, în mod surprinzător, următorul text este la fel de bine:
Uneori, te nu aveți nevoie pentru a arunca indicii, dar, având în vedere stricte aliasing regula, trebuie să fie foarte atent cu ea. Deci, orice apariție a unui pointer exprimate în cod este un loc de trebuie să verificați pentru valabilitatea acestuia. Prin urmare, n-ai scrie o inutilă pointer exprimate.
tl;dr
Într-un cuvânt: Pentru că, în C, orice apariția de o indicatorul de distributie ar trebui să ridice un steag rosu pentru cod care necesită o atenție specială, niciodată nu ar trebui să scrie inutil indicatorul de mulaje.
Side note:
void *
, de exemplu, dacă doriți să imprimați un pointer:int x = 5; printf("%p\n", (void *)&x);
Distributia este necesară aici, pentru că
printf()
este o variadic funcție, deci implicit conversii don't de lucru.void *
e nu implicite. C++ are un întreg set de diferite arome de turnare.Mi-am pus în ghips pur și simplu pentru a arăta dezaprobarea față de urât gaură în sistemul de tip, care permite de cod, cum ar fi următorul fragment pentru a compila fără diagnosticare, chiar dacă nu mulaje sunt folosite pentru a aduce despre cele rele de conversie:
Îmi doresc să am't există (și nu't în C++), și așa am făcut. Ea reprezintă gustul meu, și programarea mea politică. Am'm nu numai turnare un pointer, dar eficient, turnare un buletin de vot, și să alunge demonii din prostie. Dacă am putea't de fapt alunga prostia, atunci cel puțin să-mi exprim dorința de a face deci cu un gest de protest.
În fapt, o bună practică este să-și încheie
malloc
(și prietenii), cu funcții care returneazăunsigned char *
, și, practic, să nu folosim niciodatăvoid *
în cod. Dacă aveți nevoie de un generic pointer-la-orice-obiect, utilizați ochar * " sau " unsigned char *
, și aruncă în ambele direcții. Cel relaxare, care pot fi îngăduite, probabil, este folosind funcții, cum ar fi `memset " și " memcpy fără mulaje.Pe tema de turnare și C++ compatibilitate, daca scrii cod, astfel încât acesta compilează ca ambele C și C++ (caz în care te au a aruncat valoarea de returnare a
malloc
atunci când atribuirea altceva decâtvoid *
), puteți face un lucru foarte util pentru tine: puteți utiliza macro-uri pentru turnare care traduce în C++ stil aruncă atunci când compilarea ca C++, dar se reduce la un C cast atunci când compilarea ca C:Dacă respectați aceste macro-uri, atunci un simplu
grep
căutare de codul de bază pentru acești identificatori vă va arăta în cazul în care toate modelele sunt, astfel încât să puteți evalua dacă vreuna dintre ele sunt incorecte.Apoi, mergând mai departe, dacă în mod regulat compila codul cu C++, se va asigura utilizarea corespunzătoare a aruncat. De exemplu, dacă utilizați
strip_qual
doar pentru a elimina oconst
sauvolatile
, dar schimbări de program în așa fel încât o conversie de tip este acum implicat, vei primi un diagnostic, și va trebui să utilizați o combinație de mulaje pentru a obține dorit de conversie.Pentru a vă ajuta să adere la aceste macro-uri, GNU C++ (nu C!) compilatorul are o caracteristică frumos: un opțional de diagnosticare, care este produs în toate cazurile de C stil de mulaje.
Dacă codul C compilează ca C++, puteți folosi acest
-Wold-stil-cast
opțiune pentru a găsi toate aparițiile(tip)
de turnare a sintaxei care poate aparea in cod, și urmări aceste diagnostice înlocuindu-l cu o alegere potrivită dintre cele de mai sus macro-uri (sau o combinație, dacă este necesar).Acest tratament de conversii este cel mai mare independent justificare tehnică pentru a lucra într-o "Curat C": combinate C și C++ dialect, care, la rândul său, din punct de vedere tehnic justifică turnare valoarea de returnare a
malloc
.Eu prefer sa fac distributia, dar nu manual. Preferata mea este folosind
g_new " și " g_new0
macro-uri de volubil. Dacă glib nu este utilizat, aș adăuga similare macro-uri. Aceste macro-uri reduce duplicarea de cod, fără a compromite tip de siguranță. Dacă aveți tipul greșit, v-ar lua o implicite exprimate între non-void indicatori, care ar provoca o avertizare (eroare în C++). Dacă uitați să includă antet care defineșteg_new " și "g_new0, vei primi o eroare.
g_new" și " g_new0ia atât de aceleași argumente, spre deosebire de
malloccare are mai puține argumente decât
calloc. Trebuie doar să adăugați
0` pentru a obține zero-inițializat de memorie. Codul poate fi compilat cu un compilator C++ fără modificări.