2009-11-03 15 views
58

Cosa produrrebbe questa affermazione?Qual è la dimensione del vuoto?

void * p = (void*) malloc(sizeof(void)); 

Edit: Un'estensione alla domanda.

Se sizeof (void) restituisce 1 nel compilatore GCC, allora viene allocato 1 byte di memoria e il puntatore p punta a quel byte e p ++ verrà incrementato a 0x2346? Supponiamo che p sia 0x2345. Sto parlando di p e non * p.

+3

FYI. Questo non è standard C. In molti compilatori, questo sarebbe un errore in fase di compilazione. –

+0

perché hai bisogno di sapere. Capire questo può aiutarci a rispondere alla domanda. –

+2

Commentando la modifica: sì, in GCC (solo), l'incremento di un puntatore void ne aggiunge uno al valore. Se apprezzi la portabilità del tuo codice, non abusare della libertà che GCC ti offre. È completamente non standard. E GCC ammette tanto con '-std = c99 -pedantic'. –

risposta

42

Il tipo void non ha dimensioni; quello sarebbe un errore di compilazione. Per lo stesso motivo non puoi fare qualcosa del tipo:

void n; 

EDIT. Con mia grande sorpresa, facendo sizeof(void) realtà fa compilare in GNU C:

$ echo 'int main() { printf("%d", sizeof(void)); }' | gcc -xc -w - && ./a.out 
1 

Tuttavia, in C++ non fa:

$ echo 'int main() { printf("%d", sizeof(void)); }' | gcc -xc++ -w - && ./a.out 
<stdin>: In function 'int main()': 
<stdin>:1: error: invalid application of 'sizeof' to a void type 
<stdin>:1: error: 'printf' was not declared in this scope 
+23

Ma GCC ha un'opzione per trattare 'sizeof (void) == sizeof (char)' ... Vedi -Winter-arith –

+2

@Jon questo è per gli sciocchi dei primi anni '80 che stavano appena iniziando a imparare come programmare. Gli standard non erano ampiamente decisi. – unixman83

+3

Perché questa è la risposta accettata? – michaelsnowden

3

In C, sizeof(void) == 1 nel GCC, ma questo sembra dipendere sul tuo compilatore.

In C++, ottengo:

 
In function 'int main()': 
Line 2: error: invalid application of 'sizeof' to a void type 
compilation terminated due to -Wfatal-errors. 
+3

Solo in GCC è sizeof (void) == 1; nello standard, è un comportamento indefinito. –

+0

Aggiornato per aggiungere una nota specifica GCC. –

+0

@ JonathanLeffler: Non è semplicemente un comportamento indefinito. È una violazione del vincolo. N1570 6.5.3.4p1. –

15

Anche se void possono stare in posto per un tipo, non può effettivamente contenere un valore. Pertanto, non ha dimensioni in memoria. Ottenere la dimensione di un void non è definito.

Un voidpuntatore è semplicemente un costrutto del linguaggio che significa un puntatore non tipizzato memoria.

+1

e allora? Non dovrebbe anche nessuna struttura vuota consumare alcuna dimensione in memoria e questo dovrebbe essere un problema. Beh, in realtà mi chiedo, se le strutture vuote stanno veramente usando 0 byte in C++ (come è vero in C) sembra sizeof restituisce 1 per loro. – kriss

+1

@kriss Non sono sicuro di quello che stai dicendo, ma come hai notato tu stesso, le strutture vuote * fanno * occupano memoria per ragioni di identità dell'oggetto. –

+1

in effetti, ma non era vero in C e usare la memoria per oggetti vuoti sembra malvagio. – kriss

5

sizeof() non può essere applicato a tipi incompleti. E void è un tipo incompleto che non può essere completato.

34

Se si utilizza GCC e non si utilizzano flag di compilazione che rimuovono estensioni specifiche del compilatore, quindi è 1. GCC ha uno nonstandard extension che lo fa.

In generale, void è un tipo incompleto e non è possibile utilizzare sizeof per tipi incompleti.

+2

L'opzione '-Wpointer-arith' è implicita da' -pedantic'. Ho sempre usato '-pedantic'. :) –

+1

@jleedev In effetti, uso anche -pedantic il più possibile. Sfortunatamente, alcune intestazioni di librerie di terze parti rendono GCC -pedantic molto triste :( – hrnt

+1

+1 Davvero, perché GCC ha migliaia di estensioni inutili? –

0

Per la seconda parte della domanda: notare sizeof (void *)! = Sizeof (void). Su un arco a 32 bit, sizeof (void *) è 4 byte, quindi p ++ verrà impostato di conseguenza. La quantità di incremento di un puntatore dipende dai dati a cui punta. Quindi, sarà aumentato di 1 byte.

+1

quindi p stava puntando a 1 byte di dati poiché sizeof (void) restituisce 1 quindi p ++ significa p dovrebbe essere incrementato di 1 e non 4 ?? – Lakshmi

+1

La quantità di incremento di un puntatore dipende dai dati indica Sì. –

+0

p è di tipo void * (void pointer), non vuoto, quindi sarebbe incrementato dalla dimensione del tipo void * (che di solito è 4 nei sistemi a 32 bit). – Technowise

-1

mentre sizeof (void) forse non ha senso in sé, è importante quando si esegue una matematica con puntatori.

es.

void *p; 
while(...) 
     p++; 

Se sizeof (void) è considerato 1, funzionerà. Se sizeof (void) è considerato 0, si ottiene un ciclo infinito.

+2

Lo snippet di codice di esempio è illegale in C e C++. Alcuni compilatori lo permettono comunque. –

+0

No, non è affatto importante (sebbene gli autori di gcc abbiano pensato che lo fosse). Se vuoi fare aritmetica del puntatore su puntatori di byte, usa 'char unsigned *'. –

-1

La maggior parte dei compilatori C++ ha scelto di generare un errore di compilazione durante il tentativo di ottenere sizeof(void).

Durante la compilazione di C, gcc non è conforme e ha scelto di definire sizeof(void) come 1. Può sembrare strano, ma ha una logica. Quando si esegue l'aritmetica del puntatore aggiungendo o rimuovendo un'unità si intende aggiungere o rimuovere l'oggetto che punta alla dimensione. Quindi definire sizeof(void) come 1 aiuta a definire void* come puntatore al byte (indirizzo di memoria non tipizzato). Altrimenti si avrebbero comportamenti sorprendenti usando l'aritmetica del puntatore come p+1 == p when p è void*. Tale puntatore aritmetico sui puntatori void non è consentito in C++ ma funziona bene quando si compila C con gcc.

Il modo standard consigliato sarebbe quello di utilizzare char* per questo tipo di scopo (puntatore a byte).

Un'altra differenza simile tra C e C++ quando si utilizza sizeof si verifica quando si è definito uno struct vuoto come:

struct Empty { 
} empty; 

Utilizzando gcc come il mio compilatore C sizeof(empty) restituisce 0. Utilizzando g ++ lo stesso codice restituirà 1.

Non sono sicuro di ciò che indica gli standard C e C++ su questo punto, ma credo che definire la dimensione di alcune strutture/oggetti vuoti aiuti con la gestione dei riferimenti per evitare che due riferimenti a oggetti consecutivi diversi, il primo sia vuoto, ottieni lo stesso indirizzo. Se i riferimenti vengono implementati utilizzando i puntatori nascosti come spesso accade, assicurare un indirizzo diverso aiuterà a confrontarli.

Ma si tratta semplicemente di evitare un comportamento sorprendente (confronto tra maiuscole e minuscole dei riferimenti) mediante l'introduzione di un altro (oggetti vuoti, anche i POD consumano almeno 1 byte di memoria).

+3

"C ha scelto invece di definire sizeof (void) come 1." - No, è sbagliato. 'sizeof (void)' non è definito in C, come in C++.GCC semplicemente non è conforme a questo punto, e l'aritmetica del puntatore sui puntatori 'void' non è semplicemente definita -' void * p; p ++; 'non è valido. Persino GCC ti avviserà quando compilerai il flag '-pedantic'. E hai anche torto sul comportamento predefinito di GCC per C++: per impostazione predefinita * viene considerato come un errore *. –

+0

@Konrad: sì, sono abbastanza sicuro che non fosse vero con la versione precedente di gcc, ma quelli attuali fanno come dici tu. – kriss

+0

Almeno in C, una definizione 'struct' vuota è un errore di sintassi; Il supporto di gcc è un'estensione. Possono essere validi in C++; Non ne sono sicuro. –

6

void non ha dimensioni. In entrambi C e C++, l'espressione sizeof (void) non è valida.

In C, citando N1570 6.5.3.4 paragrafo 1:

L'operatore sizeof non si applica un'espressione che ha funzione tipo o un tipo incompleto, al nome di parentesi un tipo simile o un'espressione che designa un membro del campo di bit.

(N1570 è una bozza della ISO standard C 2011).

void è un tipo incompleto. Questo paragrafo è un vincolo , il che significa che qualsiasi compilatore C conforme deve diagnosticare qualsiasi violazione di esso. (Il messaggio di diagnostica può essere un avviso non fatale.)

Lo standard C++ 11 ha una dicitura molto simile. Entrambe le edizioni sono state pubblicate dopo che è stata posta questa domanda, ma le regole risalgono allo standard ANSI C del 1989 e ai primi standard C++. In effetti, la regola che void è un tipo incompleto a cui non è possibile applicare sizeof risale esattamente all'introduzione di void nella lingua.

gcc ha un'estensione che tratta sizeof (void) come 1. gcc non è un compilatore C conforme per default, quindi in modalità predefinita non avvertire circa sizeof (void). Estensioni come questa sono consentite anche per compilatori C completamente conformi, ma la diagnostica è ancora necessaria.

+0

Suppongo che abbiano permesso 'sizeof (void) == 1' per coerenza con il puntatore aritmetico sul puntatore' void', che è anche un'estensione [gcc] (https://gcc.gnu.org/onlinedocs/gcc/Pointer -Arith.html # Pointer-Arith). Citando dalla loro documentazione: "Una conseguenza di questo è che sizeof è permessa anche sui tipi void e on e restituisce 1.'. Tuttavia, il messaggio di diagnostica dovrebbe essere presente per impostazione predefinita per C, come richiesto da Standard. –

+0

@GrzegorzSzpetkowski: (Rispondendo un paio di anni dopo.) Sì, lo standard richiede una diagnostica, ma gcc non è un compilatore C conforme per impostazione predefinita. Logicamente, lo standard C non impone requisiti sulle implementazioni che non pretendono di conformarsi ad esso. gcc può essere reso (molto quasi) conforme alle giuste opzioni della riga di comando, come '-std = c11 -pedantic'. Con tali opzioni, emette la diagnostica richiesta. –

Problemi correlati