Perché lanciare il valore di ritorno di free per annullare?


82

Sto leggendo un libro ( Programmazione con thread POSIX di Butenhof, 1997) che utilizza C, e mi sono imbattuto nella seguente riga:

(void)free(data);

Qui, dataè solo un puntatore a una struttura allocata,

data = malloc(sizeof(my_struct_t));

Perché il risultato del freecast void?

Dalla mia comprensione di C, questo non sembra avere senso per due motivi:

  • La funzione gratuita ritorna già void
  • Il codice non utilizza il valore restituito (non è nemmeno assegnato a una variabile)

Il libro è stato scritto nel 1997. È una specie di eredità?

L'autore menziona che gli esempi sono stati eseguiti su Digital Unix 4.0d, ma non riesco ancora a immaginare un motivo per lanciare il risultato di una funzione se non intendi usare quel risultato.


Alcune possibili spiegazioni sono disponibili qui: stackoverflow.com/questions/689677/…
Timbo

3
Per curiosità, qual è la data di pubblicazione del tuo libro C? (Quale libro è?) Se è prima del 1995, potrebbe esserci qualche giustificazione per questo - i compilatori C standard non erano onnipresenti prima di allora. Se viene pubblicato dopo e contiene ancora il cast (e nessuna spiegazione del perché), preoccupati di quali altre cattive abitudini ti sta insegnando. Ottieni un libro più recente!
Jonathan Leffler il


3
@JonathanLeffler come menzionato nel mio post originale, il libro è stato pubblicato nel 1997 e utilizzava UNIX 4.0d. Il libro è "Programmazione con thread POSIX" di David R. Butenhof. Finora è stato molto istruttivo ed è stato scritto da uno dei collaboratori originali dello standard dei thread POSIX.
Adam Johnston,

6
Ho usato la mia copia di quello nell'ultima settimana - sì, è ancora utile. È stato scritto sulla cuspide dello "standard onnipresente C" (ho detto "circa 1995"). "UNIX 4.0d" suona come UNIX digitale: è lì che ha lavorato Butenhof, e la prefazione ne parla. Tratta il cast free()come una stranezza nel libro che non devi emulare. Era semi-rilevante una volta tanto tempo fa, ma non è più rilevante.
Jonathan Leffler il

Risposte:


100

Se stiamo parlando della freefunzione standard , allora è il suo prototipo

void free(void *ptr);

Pertanto il cast è completamente inutile.
Adesso qualche speculazione.

L'autore potrebbe aver dimenticato di includere l' stdlib.hintestazione che dichiara questo prototipo, quindi il compilatore sta assumendo il tipo di ritorno come int. Ora, durante l'analisi statica di questo codice, il compilatore ha avvertito del valore di ritorno inutilizzato di ciò che ritiene non voidfunzioni. Tali avvertimenti vengono solitamente messi a tacere aggiungendo il cast a void.


50
Ma nota che se il cast è stato introdotto per il motivo ipotizzato, usarlo per mettere a tacere l'avvertimento è errato . In questo caso, il compilatore attribuirà un tipo diverso da freequello che ha effettivamente, con il risultato che la chiamata ha un comportamento indefinito (supponendo che la semantica C90, in cui chiamare una funzione non dichiarata non mostri intrinsecamente UB in tutti i casi). In pratica, è plausibile che ciò comporterebbe un comportamento scorretto in buona fede su alcuni sistemi. La soluzione corretta è fornire una dichiarazione corretta per la funzione.
John Bollinger,

11
In particolare, gli esempi in "Programmazione con thread POSIX" ripetutamente non includono le intestazioni standard pertinenti. Forse questa è stata una cattiva pratica da parte dell'autore, avrebbero potuto usare una configurazione del compilatore non standard che includeva tutte le librerie standard per impostazione predefinita.
Lundin,

74

Sarebbe una cosa legacy!

Prima che esistesse uno standard C, la free()funzione sarebbe stata (implicitamente) di tipo int, poiché non esisteva ancora un tipo affidabile voidper il suo ritorno. Non è stato restituito alcun valore.

Quando il codice fu modificato per funzionare con compilatori C standard, probabilmente non includeva <stdlib.h>(perché non esisteva prima dello standard). Il vecchio codice avrebbe scritto extern char *malloc();(forse senza il extern) per le funzioni di allocazione (allo stesso modo per calloc()e realloc()), e non aveva bisogno di dichiararlo free(). E il codice avrebbe quindi lanciato il valore restituito sul tipo corretto, perché era necessario su almeno alcuni sistemi (incluso quello su cui ho imparato C).

Qualche tempo dopo, il (void)cast è stato aggiunto per dire al compilatore (o, più probabilmente, lint) che "il valore di ritorno da free()viene deliberatamente ignorato" per evitare un reclamo. Ma sarebbe stato meglio aggiungere <stdlib.h>e lasciare che la sua dichiarazione extern void free(void *vp);dicesse linto al compilatore che non c'era alcun valore da ignorare.

JFTR: A metà degli anni '80, l'ICL Perq era originariamente su un'architettura orientata alle parole e l' char *indirizzo per una posizione di memoria era un numero molto diverso dal "puntatore a qualcosa" nella stessa posizione. Era fondamentale dichiarare in char *malloc()qualche modo; era fondamentale trasmettere il risultato da esso a qualsiasi altro tipo di puntatore. Il cast ha effettivamente cambiato il numero utilizzato dalla CPU. (C'era anche molta gioia quando la memoria principale sui nostri sistemi è stata aggiornata da 1 MiB a 2 MiB - poiché il kernel usava circa 3/4 MiB, significava che i programmi utente potevano usare 1 1/4 MiB prima del paging ecc.)


9
Ho appena aperto una copia di K&R, prima edizione, che contiene un'implementazione di free()a p. 177 che ritorna implicitamente int.
ex nihilo,

9
Naturalmente - voidfu aggiunto ad alcuni sistemi (Unix System III, forse) prima che lo standard fosse rilasciato, ma ciò non faceva parte di C quando fu scritto K&R 1st Edn (1978). Una funzione che non ha restituito un valore è stata dichiarata senza un tipo restituito (il che significava che è stata restituita int) e finché non si è utilizzato il valore non restituito, non si sono verificati problemi. Lo standard C90 doveva considerare quel tipo di codice come valido - avrebbe fallito in modo disastroso come uno standard se non lo fosse. Ma C99 ha rimosso le intregole "implicite " e "dichiarazione di funzione implicita". Non tutto il codice al mondo ha raggiunto.
Jonathan Leffler il

5
Op afferma che il libro è stato scritto nel 1997. Quello di cui stai parlando è molto precoce "K&R C" pre-standard e sembra improbabile che qualcuno ne scriva affatto un libro. L'unico libro del genere che esisteva per mia conoscenza era davvero la prima edizione di K&R.
Lundin,

È stata una pratica frequente (anche se donchisciottesca) non includere le intestazioni se si pensava di poter ottenere dichiarazioni implicite, perché la gente pensava che avrebbe ridotto i tempi di costruzione.
Spencer,

Qualcuno usa un (void)cast per printf()??
Luis Colorado,

11

Questo cast non è necessario. Probabilmente non sarebbe stato al momento in quanto C era stato standardizzato sotto forma di C89.

Se lo fosse stato, sarebbe dovuto alla dichiarazione implicita . Questo di solito significava che la persona che scriveva il codice si dimenticava #include <stdlib.h>e veniva utilizzato un analizzatore statico. Questa non è la soluzione migliore e un'idea migliore sarebbe stata proprio #include <stdlib.h>invece. Ecco alcune parole di C89 sulla dichiarazione implicita:

Se l'espressione che precede l'elenco di argomenti tra parentesi in una chiamata di funzione è costituita esclusivamente da un identificatore e se non è visibile alcuna dichiarazione per questo identificatore, l'identificatore viene implicitamente dichiarato esattamente come se, nel blocco più interno contenente la chiamata di funzione, la dichiarazione

extern int identifier();

apparso.

Ma è strano perché non stanno trasmettendo il risultato di mallocnessuno dei due malloce freesono nello stesso file di intestazione.

È anche possibile che questo sia solo un errore o un modo per dire al lettore che freenon restituisce alcun risultato.


5
Solo perché una lingua viene standardizzata non significa che tutti aggiornino istantaneamente la loro toolchain e il codice per conformarsi ad essa. È plausibile che il vecchio stile "K&R" C sia rimasto bloccato per altri 8 anni. Tuttavia, sono d'accordo che è strano che uno strumento di analisi statica richiederebbe un cast per freema non per malloc.
dan04

4
@ dan04 Di solito usi il risultato di malloc;) Non sono un fan dello scrivere cose come (void) printf (...) per fermare il compilatore che sputa avvisi ma "deve compilare senza avvertimenti, anche quelli stupidi" è qualcosa che succede in molti progetti.
Richard
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.