Vraag Cast ik het resultaat van malloc?


In deze vraag, stelde iemand in a commentaar dat zou ik moeten doen niet cast het resultaat van malloc, i.e.

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

liever dan:

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

Waarom zou dit het geval zijn?


2039
2018-03-03 10:13


oorsprong


antwoorden:


Nee; u niet doen cast het resultaat, omdat:

  • Het is niet nodig, zoals void * wordt in dit geval automatisch en veilig gepromoveerd tot elk ander aanwijzertype.
  • Het voegt rommel toe aan de code, afgietsels zijn niet erg gemakkelijk te lezen (vooral als het aanwijzertype lang is).
  • Het laat je jezelf herhalen, wat over het algemeen slecht is.
  • Het kan een fout verbergen als je vergeten bent om het op te nemen <stdlib.h>. Dit kan crashes veroorzaken (of, erger nog, niet een crash veroorzaken tot veel later in een heel ander deel van de code). Overweeg wat er gebeurt als aanwijzers en gehele getallen van verschillende grootte zijn; dan verberg je een waarschuwing door te casten en verlies je mogelijk delen van je geretourneerde adres. Opmerking: vanaf C11 zijn impliciete functies verdwenen uit C en dit punt is niet langer relevant omdat er geen automatische aanname is dat niet-gedeclareerde functies retourneren int.

Ter verduidelijking: merk op dat ik zei: "je cast niet", niet "jij niet" nodig hebben casten. "Naar mijn mening is het een mislukking om de cast op te nemen, zelfs als je het goed hebt. Er zijn gewoon geen voordelen om het te doen, maar een hoop potentiële risico's, en inclusief de cast geeft aan dat je niet weet over de risico's.

Merk ook op, zoals commentatoren opmerken, dat de bovenstaande besprekingen over straight C, en niet C ++, gaan. Ik geloof heel sterk in C en C ++ als afzonderlijke talen.

Om verder toe te voegen, herhaalt uw code onnodig de typegegevens (int) die fouten kunnen veroorzaken. Het is beter om de aanwijzer die wordt gebruikt om de retourwaarde op te slaan te dereferen, om de twee samen te "vergrendelen":

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

Dit verplaatst ook de length aan de voorkant voor betere zichtbaarheid en laat de overtollige haakjes vallen met sizeof; ze zijn alleen nodig wanneer het argument een typenaam is. Veel mensen lijken dit niet te weten (of te negeren), waardoor hun code verbijzonderder wordt. Onthouden: sizeof is geen functie! :)


Tijdens het verplaatsen length naar voren mei om de zichtbaarheid in enkele zeldzame gevallen te vergroten, moet er ook op worden gelet dat in het algemene geval het beter is om de uitdrukking te schrijven als:

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

Sinds het houden van de sizeof eerst, in dit geval, zorgt ervoor dat vermenigvuldiging wordt gedaan met ten minste size_t wiskunde.

Vergelijken: malloc(sizeof *sieve * length * width) vs. malloc(length * width * sizeof *sieve) de tweede kan de length * width wanneer width en length zijn kleinere typen dan size_t.


1915
2018-03-03 10:17



In C hoeft u de retourwaarde van niet te casten malloc. De wijzer naar leegte is geretourneerd door malloc wordt automatisch geconverteerd naar het juiste type. Als u echter wilt dat uw code compileert met een C ++ - compiler, is een cast vereist. Een alternatief dat de voorkeur geniet van de community, is om het volgende te gebruiken:

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

wat je bovendien bevrijdt van je zorgen te maken over het veranderen van de rechterkant van de uitdrukking als je het type verandert sieve.

Casts zijn slecht, zoals mensen hebben opgemerkt. Speciaal aanwijzers voor aanwijzer.


327
2018-03-03 10:17



U do cast, omdat:

  • Het maakt je code draagbaarder tussen C en C ++, en zoals SO ervaring toont, beweren heel wat programmeurs dat ze in C schrijven terwijl ze echt in C ++ schrijven (of C plus lokale compiler-uitbreidingen).
  • Nalaten dit te doen kan een fout verbergen: let op alle SO-voorbeelden van verwarrend wanneer te schrijven type * versus type **.
  • Het idee dat het je ervan weerhoudt je op te merken, is mislukt #include een geschikt headerbestand mist het bos voor de bomen. Het is hetzelfde als zeggen "maak je geen zorgen over het feit dat je de compiler niet hebt gevraagd om te klagen over het niet zien van prototypes - dat vervelende stdlib.h is HET ECHTE belangrijke ding om te onthouden!"
  • Het dwingt een extra cognitieve kruiscontrole. Het plaatst het (vermeende) gewenste type vlak naast de rekenkunde die je aan het doen bent voor de onbewerkte grootte van die variabele. Ik wed dat je een SO-studie zou kunnen doen die dat laat zien malloc() bugs worden veel sneller gevangen wanneer er een cast is. Net als met beweringen verminderen annotaties die intentie onthullen, fouten.
  • Jezelf herhalen op een manier die de machine kan controleren, is vaak een Super goed idee. In feite is dat wat een bewering is, en dit gebruik van cast is een bewering. Beweringen zijn nog steeds de meest algemene techniek die we hebben om de code correct te krijgen, aangezien Turing zoveel jaren geleden met het idee kwam.

291
2018-02-14 16:15



Zoals anderen al zeiden, is het niet nodig voor C, maar voor C ++. Als je denkt dat je je C-code gaat compileren met een C ++ -compiler, om welke redenen dan ook, kun je in plaats daarvan een macro gebruiken, zoals:

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

Op die manier kun je het nog steeds op een zeer compacte manier schrijven:

int *sieve = NEW(int, 1);

en het compileert voor C en C ++.


148
2018-03-03 11:17



Van de Wikipedia

Voordelen van gieten

  • Met inbegrip van de cast kan een C-programma of -functie compileren als C ++.

  • De cast maakt versies van malloc van vóór 1989 mogelijk die oorspronkelijk een char * bevatten.

  • Gieten kan de ontwikkelaar helpen bij het vaststellen van inconsistenties in de sortering van het type als het bestemmingswijzertype verandert, met name als de aanwijzer ver van de aanroep malloc () wordt gedeclareerd (hoewel moderne compilers en statische analyseapparaten kunnen waarschuwen voor dergelijk gedrag zonder de cast te vereisen).

Nadelen van gieten

  • Onder de ANSI C-standaard is de cast overbodig.

  • Als u de cast toevoegt, wordt de header mogelijk niet opgenomen in de header stdlib.h, in   waar het prototype voor malloc wordt gevonden. In de afwezigheid van een   prototype voor malloc, de standaard vereist dat de C-compiler   neem aan dat malloc een int. retourneert. Als er geen cast is, is er een waarschuwing   uitgegeven wanneer dit gehele getal aan de aanwijzer is toegewezen; echter met   de cast, deze waarschuwing wordt niet geproduceerd, waardoor een bug wordt verborgen. Zeker   architecturen en datamodellen (zoals LP64 op 64-bit systemen, waar   lang en wijzers zijn 64-bits en int is 32-bits), deze fout kan   daadwerkelijk resulteren in ongedefinieerd gedrag, zoals impliciet verklaard   malloc retourneert een 32-bits waarde terwijl de daadwerkelijk gedefinieerde functie   retourneert een 64-bits waarde. Afhankelijk van conventies en geheugen   lay-out, kan dit leiden tot stacksplijten. Dit probleem is minder waarschijnlijk   onopgemerkt blijven in moderne compilers, zoals ze uniform produceren   waarschuwingen dat een niet-aangegeven functie is gebruikt, dus een waarschuwing   verschijnen nog steeds. Het standaardgedrag van GCC is bijvoorbeeld om een ​​te laten zien   waarschuwing die 'incompatibele impliciete declaratie van ingebouwde' aangeeft   functie "ongeacht of de cast aanwezig is of niet.

  • Als het type van de aanwijzer bij de aangifte wordt gewijzigd, kan dat één   ook moeten alle regels worden gewijzigd waar malloc wordt genoemd en cast.

Hoewel malloc zonder gieten heeft de voorkeur en de meeste ervaren programmeurs kiezen ervoor, u moet gebruiken wat u wilt, zich bewust zijn van de problemen.

d.w.z. Als u C-programma moet compileren als C ++ (hoewel dit een aparte taal is), moet u dit gebruiken malloc met gieten.


95
2017-10-09 21:23



In C kun je impliciet een lege aanwijzer naar een andere aanwijzer converteren, dus een cast is niet nodig. Als je iemand gebruikt, kan de toevallige waarnemer suggereren dat er een reden is waarom je hem nodig hebt, wat misleidend kan zijn.


94
2018-03-03 10:18



Je gooit niet het resultaat van malloc, omdat het toevoegen van zinloze rommel aan je code toevoegt.

De meest voorkomende reden waarom mensen het resultaat van malloc casten, is omdat ze niet zeker weten hoe de C-taal werkt. Dat is een waarschuwing: als u niet weet hoe een bepaald taalmechanisme werkt, dan niet doen doe een gok. Zoek het op of vraag over Stack Overflow.

Enkele opmerkingen:

  • Een lege aanwijzer kan worden geconverteerd naar / van elk ander aanwijzertype zonder expliciete cast (C11 6.3.2.3 en 6.5.16.1).

  • C ++ laat echter geen impliciete cast tussen toe void* en een ander aanwijstype. Dus in C ++ zou de cast correct zijn geweest. Maar als u in C ++ programmeert, zou u moeten gebruiken new en niet malloc (). En je zou nooit C-code moeten compileren met een C ++ -compiler.

    Als u zowel C als C ++ met dezelfde broncode moet ondersteunen, gebruikt u compilerschakelaars om de verschillen te markeren. Probeer niet om beide taalstandaarden in dezelfde code in te delen, omdat ze niet compatibel zijn.

  • Als een C-compiler geen functie kan vinden omdat u bent vergeten de header op te nemen, krijgt u daar een compiler / linker-fout. Dus als je bent vergeten om mee te nemen <stdlib.h> dat is geen buistelevisie, je zult je programma niet kunnen bouwen.

  • Over oude compilers die een versie van de standaard volgen die meer dan 25 jaar oud is, vergeten te bevatten <stdlib.h> zou resulteren in gevaarlijk gedrag. Omdat in die oude standaard functies zonder een zichtbaar prototype het retourtype impliciet hebben omgezet naar int. Het expliciet casten van het resultaat van malloc zou dan deze bug verbergen.

    Maar dat is echt een non-issue. U gebruikt geen 25 jaar oude computer, dus waarom zou u een 25 jaar oude compiler gebruiken?


83
2018-03-20 15:53



In C krijg je een impliciete conversie van void* naar een andere (gegevens) aanwijzer.


82
2018-03-03 10:16