Perché la dimensione di una funzione in C è sempre di 1 byte?


87

Quando controlliamo la dimensione di una funzione usando sizeof(), otteniamo sempre 1 byte . Cosa significa questo 1 byte?

Risposte:


80

È una violazione dei vincoli e il tuo compilatore dovrebbe diagnosticare. Se lo compila nonostante ciò, il tuo programma ha un comportamento indefinito [grazie a @Steve Jessop per il chiarimento sulla modalità di errore, e vedi la risposta di @Michael Burr per il motivo per cui alcuni compilatori lo consentono]: Da C11, 6.5.3.4./ 1:

L' sizeofoperatore non deve essere applicato a un'espressione con tipo di funzione


11
Questo è un vincolo, il che significa che in un compilatore conforme viene diagnosticato. Se il compilatore lo compila comunque (dopo averlo diagnosticato), il comportamento non è definito. Se il compilatore non lo diagnostica (cosa che ad esempio gcc non fa a meno -pedantic), hai un compilatore non conforme e ogni programma ha un comportamento indefinito.
Steve Jessop

1
Il comportamento lo colloca nella stessa categoria di un'estensione GNU C, ma non ho idea del perché qualcuno lo voglia , quindi non so perché gli autori GNU abbiano fatto di tutto per aggiungerlo.
Steve Jessop

1
@SteveJessop: Nota che questo è anche con -std=c11, no gnu11 . Questa è un'estensione del compilatore davvero strana.
Kerrek SB

6
Ooh! Scommetto che è per abilitare l'aritmetica sui puntatori a funzione, allo stesso modo in cui sizeof(void)è 1 in GNU C.
Steve Jessop

3
A proposito -std=c11: qualcuno dovrebbe riferire le -std=c*opzioni agli standard pubblicitari. Non abilitano la modalità di conformità, disabilitano semplicemente le estensioni che impedirebbero la compilazione di un programma ben formato (come typeofessere una parola chiave, poiché un programma C ben formato può usarlo come nome di variabile, ma gccper impostazione predefinita lo rifiuterebbe ). Per disabilitare ulteriormente le estensioni che consentono a programmi mal formati di passare senza diagnosi, è necessario -pedantico -pedantic-errors.
Steve Jessop

56

Questo non è un comportamento indefinito: lo standard del linguaggio C richiede una diagnostica quando si utilizza l' sizeofoperatore con un designatore di funzione (un nome di funzione) poiché è una violazione dei vincoli per l' sizeofoperatore.

Tuttavia, come estensione del linguaggio C, GCC consente l'aritmetica su voidpuntatori e puntatori a funzione, che viene eseguita trattando la dimensione di voidao come 1. Di conseguenza, l' sizeofoperatore valuterà 1per voido una funzione con GCC. Vedi http://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html#Pointer-Arith

È possibile fare in modo che GCC emetta un avviso quando si utilizza sizeofcon questi operandi utilizzando le opzioni -pedantico -Wpointer-arithdi GCC. Oppure commetti un errore con -Werror=pointer-arith.


La tua logica è viziata. C richiede messaggi diagnostici per alcuni, ma non per tutti gli UB. Non puoi affermare che qualcosa abbia definito un comportamento solo perché c'è una diagnosi.
MSalters

4
C richiede una diagnostica per tutte le violazioni dei vincoli (5.1.1.3 Diagnostica in C99 o C11). Un vincolo (3.8 in C99 / C11) è una "restrizione, sintattica o semantica, con la quale deve essere interpretata l'esposizione degli elementi del linguaggio", che sembra dire che qualcosa che non segue i vincoli non può essere interpretato .
Michael Burr

3
E per essere chiari, una violazione di un vincolo non si traduce in un comportamento indefinito. È un errore, come un errore di sintassi. Ad esempio, lo standard dice, "se un requisito" deve "o" non deve "che appare al di fuori di un vincolo viene violato, il comportamento è indefinito". Se una violazione di un vincolo risulterebbe in UB, perché lo standard dovrebbe parlare solo di "devi" e "non devi" che non sono in vincoli qui?
Michael Burr

3
Non ho davvero sizeofaffermato molto su UB tranne che una funzione non è UB (che ho menzionato praticamente solo perché altre risposte affermavano che era UB). Ma forse l'ho confuso a causa del modo in cui ho strutturato la frase. Per essere più chiari. sizeofuna funzione non è UB (come hanno affermato diverse risposte). È una violazione dei vincoli. In quanto tale, richiede una diagnosi. GCC lo consente come estensione.
Michael Burr

2
@KerrekSB: l'OP non riceve una diagnostica perché presumibilmente sta usando GCC, che consente questo uso come estensione del linguaggio C.
Michael Burr

13

Significa che l'autore del compilatore ha deciso un valore di 1 piuttosto che far volare i demoni dal tuo naso (in effetti, è stato un altro uso indefinito sizeofche ci ha dato quell'espressione: "il compilatore C stesso DEVE emettere una diagnostica SE questa è la prima richiesta diagnostica risultante dal tuo programma, e quindi PU esso stesso far volare i demoni dal tuo naso (che, a proposito, potrebbe benissimo ESSERE il messaggio diagnostico documentato) così come POTREBBE emettere ulteriori diagnosi per ulteriori violazioni delle regole o dei vincoli della sintassi (o, del resto, per qualsiasi motivo scelga). " https://groups.google.com/forum/?fromgroups=#!msg/comp.std.c/ycpVKxTZkgw/S2hHdTbv4d8J

Da questo deriva il termine gergale "demoni nasali" per qualunque cosa un compilatore decida di fare in risposta a un costrutto indefinito. 1è il demone nasale di questo compilatore per questo caso.


@ IlmariKaronen Devo ammettere però che c'è una ragione per cui la maggior parte delle mie risposte su C (e C ++) sono su principi generali indipendenti dal linguaggio o su pepite storiche del genere. La mia esperienza C rasenta la storia in sé :)
Jon Hanna

7

Come altri hanno sottolineato, sizeof () può accettare qualsiasi identificatore valido, ma non restituirà un risultato valido (onestamente vero e valido) per i nomi delle funzioni. Inoltre, può sicuramente, o meno, provocare la sindrome dei "demoni fuori dal naso".

Se vuoi profilare la dimensione della funzione del tuo programma, controlla la mappa del linker, che può essere trovata nella directory dei risultati intermedi (quella in cui le cose sono compilate in .obj / .o o dove si trova l'immagine / eseguibile risultante). A volte c'è un'opzione per generare o meno questo file di mappa ... dipende dal compilatore / linker.

Se vuoi la dimensione di un puntatore a una funzione, sono tutte della stessa dimensione, la dimensione di una parola di indirizzamento sulla tua cpu.


1
Che tipo di affermazione è "sicuramente può o no" ??? Non è vero letteralmente per tutto?
Kerrek SB

@KerrekSB sì, ma qui può o non può fare nulla, ed essere comunque nel rispetto delle regole. È vero che un compilatore può o non può rifiutarsi di compilare, int x = 1;ma solo uno di questi è consentito per un compilatore conforme agli standard. Con sizeof()essere applicata a una funzione, si può o non può restituire un valore impostato, o rifiutare di compilazione, o restituire un valore casuale in base a ciò che c'è in un particolare registro al momento. I demoni nasali letterali sono improbabili, ma entro la lettera dello standard.
Jon Hanna

@kerrek Potrebbe essere vero per niente o potrebbe non essere falso per niente ... guardalo come sfocato illogico.
jpinto3912

1
Se vuoi conoscere la dimensione di un puntatore a una funzione, applica sizeofa un puntatore a una funzione.
alexis
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.