Frage

Betrachten Sie diesen Code.

#define A 5
#define B 3

int difference = A - B;

Ist der Wert von „Differenz“ in der Kompilierungszeit fest als „2“ codiert oder wird er zur Laufzeit berechnet?

War es hilfreich?

Lösung

Der A Und B Makros sind etwas ablenkend.Das:

#define A 5
#define B 3

int difference = A - B;

entspricht genau diesem:

int difference = 5 - 3;

Lassen Sie uns also Letzteres besprechen.

5 - 3 ist ein beständiger Ausdruck, ein Ausdruck, der „während der Übersetzung und nicht zur Laufzeit ausgewertet werden kann und dementsprechend an jeder Stelle verwendet werden kann, an der sich eine Konstante befindet“.Es ist auch ein *ganzzahliger konstanter Ausdruck.Beispielsweise muss eine Fallbezeichnung ein ganzzahliger Konstantenausdruck sein, Sie könnten also Folgendes schreiben:

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

oder dieses:

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

Beachten Sie jedoch, dass die Definition dies besagt kann sein während der Übersetzung ausgewertet, nicht dass es so sein muss.Es gibt einige Kontexte, die konstante Ausdrücke und in diesen Kontexten den Ausdruck erfordern muss zur Kompilierungszeit ausgewertet werden.

Aber davon ausgehend difference innerhalb einer Funktion deklariert wird, ist der Initialisierer keiner dieser Kontexte.

Jeder Compiler, der das Geld wert ist, das Sie dafür bezahlen (auch wenn er kostenlos ist), wird reduziert 5 - 3 Zu 2 zur Kompilierungszeit und generieren Sie Code, der den Wert speichert 2 In difference.Dies ist jedoch nicht erforderlich.Der C-Standard spezifiziert die Verhalten von Programmen;Es wird nicht angegeben, wie dieses Verhalten implementiert werden muss.Man kann jedoch mit Sicherheit davon ausgehen, dass der von Ihnen verwendete Compiler ersetzt wird 5 - 3 von 2.

Auch wenn Sie schreiben:

int difference = 2;

Ein Compiler könnte legal Code generieren, der den Wert lädt 5 in ein Register, subtrahiert 3 daraus und speichert den Inhalt des Registers darin difference.Das wäre eine dumme Sache, aber der Sprachstandard schließt es nicht aus.

Solange das Endergebnis das ist difference hat den Wert 2, Dem Sprachstandard ist es egal, wie es gemacht wird.

Wenn Sie hingegen schreiben:

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

dann der Compiler muss Berechnen Sie das Ergebnis, damit der Fehler diagnostiziert werden kann (Sie können nicht zwei Fallbezeichnungen mit demselben Wert haben.

Schließlich, wenn Sie definieren difference im Dateibereich (außerhalb einer Funktion), dann der Anfangswert tut müssen konstant sein.Aber der eigentliche Unterschied besteht in diesem Fall nicht darin, ob 5 - 3 Wird zur Kompilierungszeit ausgewertet, es geht darum, ob Sie es sind erlaubt einen nicht konstanten Ausdruck verwenden.

Referenz:Der neueste Entwurf des C-Standards von 2011 ist N1570 (großes PDF);Konstante Ausdrücke werden in Abschnitt 6.6 besprochen.

Andere Tipps

Der Standard spezifiziert so etwas nicht.Es sagt nichts über mögliche Optimierungen wie diese aus (und das aus gutem Grund).Ein Standard definiert die Semantik, nicht die Implementierung.

Warum schauen Sie sich nicht die Demontage Ihres Compilers an?Das wird Ihnen eine definitive Antwort geben.

...

Also lasst uns das tun.

Hier ist die Ausgabe von 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  

Wie Sie sehen können, hat es lediglich das Auftreten von ersetzt x mit einem statischen Wert von 2 und schob es für den Aufruf auf den Stapel cout.Der Ausdruck wurde zur Laufzeit nicht ausgewertet.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top