Skal jeg kaste resultatet af malloc?

I dette spørgsmål var der nogen der i en kommentar foreslog, at jeg ikke skulle kaste resultatet af malloc, dvs.

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

i stedet for:

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

Hvorfor skulle dette være tilfældet?

Løsning

Nej; du kaster ikke resultatet, da:

  • Det er unødvendigt, da void * automatisk og sikkert promoveres til enhver anden pointertype i dette tilfælde.
  • Det tilføjer rod i koden, casts er ikke særlig lette at læse (især hvis pointertypen er lang).
  • Det får dig til at gentage dig selv, hvilket generelt er dårligt.
  • Det kan skjule en fejl, hvis du har glemt at inkludere `. Dette kan forårsage nedbrud (eller, endnu værre, *ikke* forårsage et nedbrud før langt senere i en helt anden del af koden). Tænk på hvad der sker hvis pointere og integers har forskellig størrelse; så skjuler du en advarsel ved at caster og kan miste bits af din returnerede adresse. Bemærk: fra og med C99 er implicitte funktioner forsvundet fra C, og dette punkt er ikke længere relevant, da der ikke længere er nogen automatisk antagelse om, at udeklarerede funktioner returnererint`.

Som en præcisering skal du bemærke, at jeg sagde "du skal ikke caste", ikke "du behøver ikke at caste". Efter min mening er det en fejl at inkludere cast, selv hvis du har det rigtigt. Der er simpelthen ingen fordele ved at gøre det, men en masse potentielle risici, og at medtage gipsen indikerer, at du ikke kender til risiciene.

Bemærk også, som kommentatorer påpeger, at ovenstående taler om ren C, ikke C++. Jeg tror meget stærkt på C og C++ som separate sprog.

For yderligere at tilføje, at din kode unødigt gentager typeoplysningerne (int), hvilket kan forårsage fejl. Det er bedre at de-referere den pointer, der bruges til at gemme returværdien, for at "låse" de to sammen:

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

Dette flytter også length til forsiden for at øge synligheden, og dropper de overflødige parenteser med sizeof; de er kun nødvendige når argumentet er et typenavn. Mange mennesker synes ikke at vide (eller ignorerer) dette, hvilket gør deres kode mere omstændelig. Husk: sizeof er ikke en funktion! :)


Selvom det kan øge synligheden i nogle sjældne tilfælde at flytte length foran, bør man også være opmærksom på, at det i det generelle tilfælde bør være bedre at skrive udtrykket som:

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

Da det at holde sizeof først, i dette tilfælde, sikrer, at multiplikationen udføres med mindst size_t matematik.

Sammenlign: Sammenlign: malloc(sizeof *sieve * length * width) vs. malloc(length * width * sizeof *sieve) den anden kan overløbe length * width når width og length er mindre typer end size_t.

Kommentarer (32)

I C er det ikke nødvendigt at kaste returværdien af malloc. Pointeren til void, der returneres af malloc, konverteres automatisk til den korrekte type. Men hvis du vil have din kode til at kompilere med en C++-compiler, er det nødvendigt med en cast. Et foretrukket alternativ blandt fællesskabet er at bruge følgende:

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

som desuden befrier dig for at skulle bekymre dig om at ændre højre side af udtrykket, hvis du nogensinde ændrer typen af sieve.

Casts er dårlige, som folk har påpeget. Specielt pointer casts.

Kommentarer (8)

I C får du en implicit konvertering fra void* til en hvilken som helst anden (data)pointer.

Kommentarer (2)