Domanda Do il risultato di malloc?


In questa domanda, qualcuno ha suggerito in a commento che dovrei non lancia il risultato di malloc, cioè

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

piuttosto che:

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

Perché dovrebbe essere così?


2039
2018-03-03 10:13


origine


risposte:


No; tu non lancia il risultato, poiché:

  • Non è necessario, come void * in questo caso viene promosso automaticamente e in sicurezza a qualsiasi altro tipo di puntatore.
  • Aggiunge clutter al codice, i cast non sono molto facili da leggere (specialmente se il tipo di puntatore è lungo).
  • Ti fa ripetere te stesso, che è generalmente cattivo.
  • Può nascondere un errore se hai dimenticato di includere <stdlib.h>. Questo può causare crash (o, peggio, non causare un crash fino ad un momento successivo in una parte totalmente diversa del codice). Considera cosa succede se i puntatori e gli interi sono di dimensioni diverse; quindi stai nascondendo un avviso tramite il cast e potresti perdere parti dell'indirizzo restituito. Nota: a partire da C11 le funzioni implicite sono passate da C, e questo punto non è più rilevante in quanto non esiste un'assunzione automatica che le funzioni non dichiarate restituiscano int.

Come chiarimento, nota che ho detto "non si cast", non "non si bisogno "Secondo me, è un fallimento includere il cast, anche se hai capito bene, semplicemente non ci sono benefici nel farlo, ma un sacco di potenziali rischi, e incluso il cast indica che non lo sai sui rischi

Si noti inoltre, come sottolineano i commentatori, che quanto sopra parla di diritto C, non di C ++. Credo fermamente in C e C ++ come lingue separate.

Per aggiungere ulteriori informazioni, il codice ripete inutilmente le informazioni sul tipo (int) che può causare errori. È meglio dereferenziare il puntatore utilizzato per memorizzare il valore di ritorno, per "bloccare" i due insieme:

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

Questo sposta anche il length in primo piano per una maggiore visibilità e con le parentesi ridondanti sizeof; essi sono solo necessari quando l'argomento è un nome di tipo. Molte persone sembrano non sapere (o ignorare) questo, il che rende il loro codice più dettagliato. Ricorda: sizeof non è una funzione! :)


Durante lo spostamento length davanti potrebbe aumentare la visibilità in alcuni rari casi, si dovrebbe anche prestare attenzione che nel caso generale, dovrebbe essere meglio scrivere l'espressione come:

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

Dal momento che mantenere il sizeof prima, in questo caso, assicura che la moltiplicazione sia fatta almeno con size_t matematica.

Confrontare: malloc(sizeof *sieve * length * width) vs. malloc(length * width * sizeof *sieve) il secondo potrebbe traboccare il length * width quando width e length sono più piccoli tipi di size_t.


1915
2018-03-03 10:17



In C, non è necessario eseguire il cast del valore restituito di malloc. Il puntatore a void restituito da malloc viene convertito automaticamente nel tipo corretto. Tuttavia, se vuoi che il tuo codice venga compilato con un compilatore C ++, è necessario un cast. Un'alternativa preferita tra le comunità è di utilizzare quanto segue:

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

che ti libera inoltre dal dovermi preoccupare di cambiare il lato destro dell'espressione se mai cambi il tipo di sieve.

I cast sono cattivi, come hanno sottolineato le persone. Puntatori appositamente puntati.


327
2018-03-03 10:17



tu fare cast, perché:

  • Rende il tuo codice più portatile tra C e C ++, e come mostra l'esperienza SO, molti programmatori sostengono di scrivere in C quando stanno davvero scrivendo in C ++ (o C oltre alle estensioni del compilatore locale).
  • Non riuscendo a farlo può nascondere un errore: nota tutti gli esempi SO di confusione quando scrivere type * contro type **.
  • L'idea che ti impedisce di notare che non sei riuscito a farlo #include manca un file di intestazione appropriato la foresta per gli alberi. È come dire "non ti preoccupare del fatto che non hai chiesto al compilatore di lamentarsi del fatto di non vedere i prototipi - che fastidioso stdlib.h è la vera cosa importante da ricordare!"
  • Forza un extra controllo cognitivo incrociato. Mette il (presunto) tipo desiderato proprio accanto all'aritmetica che stai facendo per la dimensione grezza di quella variabile. Scommetto che potresti fare uno studio SO che lo dimostra malloc() i bug vengono catturati molto più velocemente quando c'è un cast. Come per le asserzioni, le annotazioni che rivelano l'intenzione diminuiscono i bug.
  • Ripetersi in un modo che la macchina può controllare spesso è a grande idea. In realtà, questo è ciò che è un'affermazione, e questo uso del cast è un'asserzione. Le asserzioni sono ancora la tecnica più generale che abbiamo per ottenere il codice corretto, dal momento che Turing ha avuto l'idea di tanti anni fa.

291
2018-02-14 16:15



Come altri affermato, non è necessario per C, ma per C ++. Se pensi di compilare il tuo codice C con un compilatore C ++, per quale motivo, puoi usare una macro invece, come:

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

In questo modo puoi ancora scriverlo in un modo molto compatto:

int *sieve = NEW(int, 1);

e verrà compilato per C e C ++.


148
2018-03-03 11:17



Dal Wikipedia

Vantaggi del casting

  • Includere il cast potrebbe consentire a un programma o una funzione C di compilare come C ++.

  • Il cast consente versioni di malloc precedenti al 1989 che originariamente restituivano un char *.

  • Il cast può aiutare lo sviluppatore a identificare incongruenze nel dimensionamento del tipo in caso di cambiamento del tipo di puntatore di destinazione, in particolare se il puntatore è dichiarato lontano dalla chiamata malloc (), anche se i moderni compilatori e analizzatori statici possono avvisare su tale comportamento senza richiedere il cast.

Svantaggi del casting

  • Sotto lo standard ANSI C, il cast è ridondante.

  • L'aggiunta del cast può mascherare l'errore di includere l'intestazione stdlib.h, in   quale viene trovato il prototipo per malloc. In assenza di a   prototipo per malloc, lo standard richiede che il compilatore C   supponiamo che malloc restituisca un int. Se non c'è cast, è un avvertimento   emesso quando questo intero è assegnato al puntatore; tuttavia, con   il cast, questo avviso non viene prodotto, nascondendo un bug. Su certo   architetture e modelli di dati (come LP64 su sistemi a 64 bit, dove   lungo e puntatori sono 64-bit e int è 32-bit), questo errore può   in realtà si traduce in un comportamento indefinito, come implicitamente dichiarato   malloc restituisce un valore a 32 bit mentre la funzione effettivamente definita   restituisce un valore a 64 bit. A seconda delle convenzioni di chiamata e della memoria   layout, questo potrebbe causare lo smash stack. Questo problema è meno probabile   passare inosservati nei compilatori moderni, come producono in modo uniforme   avverte che è stata utilizzata una funzione non dichiarata, quindi verrà visualizzato un avviso   appaiono ancora. Ad esempio, il comportamento predefinito di GCC è mostrare a   avviso che legge "dichiarazione implicita incompatibile di built-in   funzione "indipendentemente dal fatto che il cast sia presente o meno.

  • Se il tipo del puntatore è cambiato nella sua dichiarazione, si può   inoltre, è necessario modificare tutte le linee in cui viene chiamato malloc e cast.

Sebbene malloc senza casting è il metodo preferito e la maggior parte dei programmatori esperti lo sceglie, dovresti usare quello che ti piace avere a conoscenza dei problemi.

Ad esempio: se è necessario compilare il programma C come C ++ (anche se si tratta di una lingua separata), si dovrebbe usare malloc con il casting.


95
2017-10-09 21:23



In C è possibile convertire implicitamente un puntatore void in qualsiasi altro tipo di puntatore, quindi un cast non è necessario. Usarne uno può suggerire all'osservatore casuale che ci sono alcune ragioni per cui è necessario, il che può essere fuorviante.


94
2018-03-03 10:18



Non lanci il risultato di malloc, perché così facendo aggiungi clutter inutili al tuo codice.

Il motivo più comune per cui la gente lancia il risultato di malloc è perché non sono sicuri di come funziona il linguaggio C. Questo è un segnale di avvertimento: se non sai come funziona un particolare meccanismo linguistico, allora non fare una supposizione Cercalo o chiedi su Stack Overflow.

Alcuni commenti:

  • Un puntatore vuoto può essere convertito in / da qualsiasi altro tipo di puntatore senza un cast esplicito (C11 6.3.2.3 e 6.5.16.1).

  • Tuttavia, C ++ non consentirà un cast implicito tra void* e un altro tipo di puntatore. Quindi in C ++, il cast sarebbe stato corretto. Ma se programmi in C ++, dovresti usare new e non malloc (). E non dovresti mai compilare il codice C usando un compilatore C ++.

    Se è necessario supportare sia C che C ++ con lo stesso codice sorgente, utilizzare le opzioni del compilatore per contrassegnare le differenze. Non tentare di saziare entrambi gli standard di lingua con lo stesso codice, perché non sono compatibili.

  • Se un compilatore C non riesce a trovare una funzione perché hai dimenticato di includere l'intestazione, otterrai un errore del compilatore / linker. Quindi se hai dimenticato di includere <stdlib.h> non è un grosso problema, non sarai in grado di costruire il tuo programma.

  • Su antichi compilatori che seguono una versione dello standard che ha più di 25 anni, dimenticando di includere <stdlib.h> comporterebbe un comportamento pericoloso. Perché in quello standard antico, le funzioni senza un prototipo visibile convertivano implicitamente il tipo di ritorno a int. Lanciare esplicitamente il risultato di malloc nasconderebbe questo bug.

    Ma questo è davvero un non-problema. Non stai usando un computer di 25 anni, quindi perché dovresti usare un compilatore di 25 anni?


83
2018-03-20 15:53