2012-04-09 17 views
22

Ho letto che l'operatore sizeof in C viene interpretato in fase di compilazione e poiché al momento della compilazione il compilatore conosce la dimensione dell'array e il suo tipo, sizeof è utilizzato per calcolare il numero di byte occupati dall'array. Ma come funziona sizeof working per il seguente codice:Come sizeof (array) funziona in fase di runtime?

#include<stdio.h> 
#include<string.h> 
int main() 
{ 
    int n; 
    scanf("%d",&n); 
    int a[n]; 
    int s=sizeof(a); 
    printf("%d",s); 
    return 0; 
} 

Qui dimensione della matrice non è noto al momento della compilazione, allora come sta funzionando correttamente?

+0

possibile duplicato di [Utilizzo di sizeof con una matrice allocata dinamicamente] (http://stackoverflow.com/questions/2731500/using-sizeof-with-a-dinamically-allocated-array) –

+3

Le matrici di lunghezza variabile rappresentano un'eccezione, per loro, 'sizeof' viene valutato in fase di esecuzione, non in fase di compilazione. –

+2

@ MДΓΓБДLL No, si tratta di cose 'malloc'ed, non di VLA. –

risposta

26

sizeof viene sempre calcolato in fase di compilazione in C89. Dal momento che C99 e matrici di lunghezza variabile, viene calcolato in fase di esecuzione quando una matrice di lunghezza variabile fa parte dell'espressione nell'operando sizeof.

Uguale per la valutazione dell'operando sizeof: non viene valutato in C89 ma in C99 se l'operando è di tipo a lunghezza variabile viene valutato. Ad esempio:

int n = 5; 
sizeof (int [n++]); 

// n is now 6 
+0

Grazie ora. –

+0

Cosa significa quel 'int [n ++]'? La prima volta lo vedo in linguaggio C –

+1

@TheMask 'int [N]' è un nome di tipo C. È un array 'N' di' int'. Quando 'N' non è una costante come nella risposta, è un * array di lunghezza variabile *. – ouah

2

In tal caso, sizeof() viene valutato in fase di esecuzione. Il compilatore, poiché sa che la dimensione di a si basa sul valore di n al momento della dichiarazione dell'array, genera codice per utilizzare il valore appropriato di n per restituire un valore ragionevole per sizeof().

In C99, non tutti gli usi di sizeof() possono essere completamente valutati in fase di compilazione e ridotti a una costante di runtime.

+0

Si noti che il compilatore potrebbe usare un vecchio valore per 'n'; per esempio 'int n = 5; char a [n]; n = 10; return sizeof (a); 'restituisce sempre 5, non 10. –

+0

Esatto, cambierò la mia risposta. –

+0

@greg no, questo è un VLA –

2

Ho letto che sizeof di C viene interpretato in fase di compilazione

sizeof è determinato in fase di compilazione in tutti i casi a parte per VLA. Per un VLA, sizeof viene valutato in fase di esecuzione.

13

Poiché si sta applicando sizeof a un array di lunghezza variabile, la cui dimensione non è conosciuta completamente in fase di compilazione, il compilatore deve generare codice per fare parte di esso in fase di esecuzione.

gcc 4.6.3 di ottimizzatori di alto livello convertire il codice che avete mostrato per

scanf ("%d", &n); 
t12 = (long unsigned int) n; 
t13 = t12 * 4; 
__builtin_alloca (t13); 
t16 = (unsigned int) t12; 
t17 = t16 * 4; 
s18 = (int) t17; 
printf ("%d", s18); 

fa che spiegano cosa sta succedendo sotto il cofano? (Non lasciatevi scoraggiare dal numero stupido di variabili temporanee - questo è un artefatto del programma che si trova nel formato static single assignment nel punto in cui ho chiesto un dump di codice intermedio.)

+1

Come è stato generato questo codice intermedio con gcc? –

+4

Inserisci il file che vuoi compilare in una directory da solo, quindi invoca gcc su di esso da una shell in quella directory, aggiungendo '-fdump-tree-all' alle opzioni della riga di comando (probabilmente vuoi' -S' e' -O2' pure). È necessario isolare il file in una directory scratch perché questo genererà circa 100 file di codice intermedio (e questa è solo la prima metà della pipeline di ottimizzazione; '-fdump-rtl-all' fornirà altri file 60ish). È quindi possibile leggerli in sequenza (sono numerati) – zwol

+0

@TheMask (continua) I dump "tree" sono generalmente più utili dei dump "rtl" a meno che non si stia tentando di eseguire il debug di uno dei "back end" di GCC (codice generazione per un'architettura specifica). È possibile limitare l'output a un pass specifico di interesse dicendo '-fdump- (tree | rtl) -PASSNAME' invece di' -all', dove PASSNAME è la parola dopo il numero nel nome file del dump. Vedi http://gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/Debugging-Options.html#index-d-589 (fai scorrere verso l'alto un po ', poi leggi da lì fino alla fine del documento) per maggiori dettagli. – zwol

7

Dallo standard C99 :

6.5.3.4

l'operatore sizeof produce la dimensione (in byte) del suo operando, che può essere un espressione o il nome di un tipo tra parentesi. La dimensione è determinata dal tipo di dell'operando. Il risultato è un numero intero. Se il tipo di operando è un tipo a lunghezza variabile , l'operando viene valutato; in caso contrario, l'operando non viene valutato e il risultato è una costante intera di .

1

Indipendentemente dal fatto sizeof viene calcolato in fase di compilazione o esecuzione (o più formalmente parlando, se il risultato è un numero intero espressione costante), il risultato di sizeof è puramente basato sulla tipo del suo argomento e non ha alcun nascosto dati che accompagnano la matrice a lunghezza variabile stessa. Naturalmente quando sizeof viene applicato a un tipo variabilmente modificato, il programma generato deve tenere traccia di quella dimensione da qualche parte. Ma potrebbe semplicemente ricalcolarlo se l'espressione fosse abbastanza semplice e le variabili da cui originariamente derivava la lunghezza non possano essere cambiate. Oppure, potrebbe memorizzare la dimensione del tipo da qualche parte (essenzialmente in una variabile locale nascosta), ma questo non sarebbe collegato all'oggetto VLA in alcun modo osservabile (ad esempio, se si passa un puntatore al primo elemento del VLA a un'altra funzione, quel puntatore non può essere utilizzato per recuperare la lunghezza VLA).

Problemi correlati