Domanda

Considera questo codice;

#define A 5
#define B 3

int difference = A - B;
.

Il valore della "differenza" è hardcoded come "2" in tempo di compilazione, o viene calcolato in runtime?

È stato utile?

Soluzione

Le macro di A e B sono un po 'di distrazione. Questo:

#define A 5
#define B 3

int difference = A - B;
.

è esattamente equivalente a questo:

int difference = 5 - 3;
.

Quindi discutiamo quest'ultimo.

5 - 3 è un'espressione costante , che è un'espressione che "può essere valutata durante la traduzione anziché runtime, e di conseguenza può essere utilizzato in qualsiasi luogo che una costante può essere". È anche un'espressione costante * intera ". Ad esempio, un'etichetta caso deve essere un'espressione costante intera, in modo da poter scrivere questo:

switch (foo) {
    case 2: /* this is a constant */
    ...
}
.

O questo:

switch (foo) {
    case 5 - 3: /* this is a constant expression */
    ...
}
.

Ma nota che la definizione dice che può essere valutato durante la traduzione, non che deve essere. Ci sono alcuni contesti che richiedono espressioni costanti e in quei contesti l'espressione deve essere valutata a tempo di compilazione.

Ma supponendo che difference sia dichiarato all'interno di qualche funzione, l'inizializzazione non è uno di questi contesti.

Qualsiasi compilatore vale ciò che si paga per questo (anche se è gratuito) ridurrà 5 - 3 a 2 al momento della compilazione e generare il codice che memorizza il valore 2 in difference. Ma non è necessario farlo. Lo standard C specifica il comportamento dei programmi; Non specifica come tale comportamento deve essere implementato. Ma è sicuro presumere che qualunque sia il compilatore che utilizzi sostituirà 5 - 3 da 2.

Anche se scrivi:

int difference = 2;
.

Un compilatore potrebbe generare legalmente il codice che carichi il valore 5 in un registro, sottrae la sottrae 3 da esso e memorizza il contenuto del registro in difference. Questa sarebbe una cosa stupida da fare, ma lo standard linguistico non lo esclude.

Finché il risultato finale è che difference ha il valore 2, lo standard linguistico non importa come è fatto.

D'altra parte, se scrivi:

switch (foo) {
    case 5 - 3: /* ... */
    case 2:     /* ... */
}
.

Quindi il compilatore deve Computa il risultato in modo che possa diagnosticare l'errore (non è possibile avere due etichette di caso con lo stesso valore.

Infine, se si definisce difference sullo scope del file (al di fuori della funzione), il valore iniziale deve essere costante. Ma la vera distinzione in tal caso non è se 5 - 3 verrà valutato a tempo di compilazione, è se sei consentito di utilizzare un'espressione non costante.

Riferimento: l'ultima bozza dello standard C 2011 è N1570 (PDF grande); Le espressioni costanti sono discusse nella Sezione 6.6.

Altri suggerimenti

Lo standard non specifica questo genere di cose.Non dice nulla di potenziali ottimizzazioni come questa (e per una buona ragione. Uno standard definisce semantica, non implementazione).

Perché non guardare lo smontaggio per il tuo compilatore?Questo ti darà una risposta definitiva.

...

Quindi facciamolo.

Ecco l'output da VC ++ 10:

#include <iostream>

#define A 5
#define B 3

int main() {
    int x = A - B;
    std::cout << x;  // make sure the compiler doesn't toss it away
010A1000  mov         ecx,dword ptr [__imp_std::cout (10A2048h)]  
010A1006  push        2  
010A1008  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (10A2044h)]  
    return 0;
010A100E  xor         eax,eax  
.

Come puoi vedere, ha appena sostituito il verificarsi di x con un valore statico di 2 e lo ha spinto sullo stack per la chiamata a cout.Non ha valutato l'espressione in fase di esecuzione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top