Hier ist der Code, der in dev c ++ - Fenstern kompiliert wurde:
#include <stdio.h>
int main() {
int x = 5;
printf("%d and ", sizeof(x++)); // note 1
printf("%d\n", x); // note 2
return 0;
}
Ich erwarte, dass x
nach der Ausführung von note 1 6 ist. Die Ausgabe ist jedoch:
4 and 5
Kann jemand erklären, warum x
nicht nach note 1 inkrementiert?
Aus dem C99 Standard (der Schwerpunkt liegt bei mir)
6.5.3.4/2
Der Operator sizeof gibt die Größe (in Bytes) seines Operanden an. Dies kann ein Ausdruck oder der Name eines Typs in Klammern sein. Die Größe wird aus dem Typ des Operanden bestimmt. Das Ergebnis ist eine ganze Zahl. Wenn der Typ des Operanden ein Array-Typ mit variabler Länge ist, wird der Operand ausgewertet. Andernfalls wird der Operand nicht ausgewertet und das Ergebnis ist eine Ganzzahlkonstante.
sizeof
ist ein Operator zur Kompilierungszeit , also zum Zeitpunkt der Kompilierung sizeof
und sein Operand werden durch den Ergebniswert ersetzt. Der Operand wird nicht ausgewertet (außer wenn es sich um ein Array mit variabler Länge handelt). Nur der Typ des Ergebnisses ist von Bedeutung.
short func(short x) { // this function never gets called !!
printf("%d", x); // this print never happens
return x;
}
int main() {
printf("%d", sizeof(func(3))); // all that matters to sizeof is the
// return type of the function.
return 0;
}
Ausgabe:
2
as short
belegt 2 Bytes auf meinem Computer.
Ändern des Rückgabetyps der Funktion in double
:
double func(short x) {
// rest all same
gibt 8
als Ausgabe aus.
sizeof(foo)
ist sehr bemüht, die Größe eines Ausdrucks zur Kompilierzeit zu ermitteln:
6.5.3.4:
Der Operator sizeof gibt die Größe (in Bytes) seines Operanden an. Dies kann ein .__ sein. Ausdruck oder der Name in Klammern eines Typs. Die Größe wird vom Typ von .__ bestimmt. der Operand Das Ergebnis ist eine ganze Zahl. Wenn der Typ des Operanden ein Array mit variabler Länge ist Typ wird der Operand ausgewertet; Andernfalls wird der Operand nicht ausgewertet und das Ergebnis ist eine Ganzzahlkonstante.
Kurz gesagt: Arrays mit variabler Länge, die zur Laufzeit ausgeführt werden. (Hinweis: Arrays mit variabler Länge sind eine bestimmte Funktion - nicht mit malloc(3)
zugeordnete Arrays.) Andernfalls wird nur der type des Ausdrucks berechnet, und zwar zur Kompilierzeit.
sizeof
ist ein eingebauter Operator zur Kompilierzeit und ist nicht eine Funktion. Dies wird sehr deutlich in den Fällen, in denen Sie es ohne Klammern verwenden können:
(sizeof x) //this also works
Hinweis
Diese Antwort wurde aus einem Duplikat zusammengeführt, was das spätere Datum erklärt.
Original
Mit Ausnahme von Arrays mit variabler Längesizeof wertet seine Argumente nicht aus. Wir können dies aus dem Entwurf des C99-Standardabschnitts ersehen. 6.5.3.4
Der Operator size Absatz 2, der sagt:
Der Operator sizeof gibt die Größe (in Bytes) seines Operanden an. Dies kann ein .__ sein. Ausdruck oder der Name in Klammern eines Typs. Die Größe wird vom Typ von .__ bestimmt. der Operand Das Ergebnis ist eine ganze Zahl. Wenn der Typ des Operanden ein Array mit variabler Länge ist Typ wird der Operand ausgewertet; Andernfalls wird der Operand nicht ausgewertet und das Ergebnis ist eine Ganzzahlkonstante.
In einem Kommentar (jetzt entfernt) wurde gefragt, ob etwas zur Laufzeit ausgewertet wird:
sizeof( char[x++] ) ;
und tatsächlich würde so etwas auch funktionieren (SEHEN SIE BEIDE LIVE):
sizeof( char[func()] ) ;
da sie beide Arrays mit variabler Länge sind. Ich sehe zwar in beiden keinen praktischen Nutzen.
Beachten Sie, dass Arrays mit variabler Länge im Abschnitt Entwurf C99-Standard Abschnitt 6.7.5.2
Array-Deklaratoren Absatz 4 behandelt werden:
[...] Wenn die Größe ein ganzzahliger konstanter Ausdruck ist und der Elementtyp eine bekannte konstante Größe hat, ist der Arraytyp kein Arraytyp mit variabler Länge. ansonsten ist der Array-Typ ein Array-Typ mit variabler Länge.
Aktualisieren
In C11 ändert sich die Antwort für den VLA-Fall. In bestimmten Fällen ist nicht angegeben, ob der Größenausdruck ausgewertet wird oder nicht. Aus Abschnitt 6.7.6.2
Array-Deklaratoren, der sagt:
[...] Wo ein Größenausdruck Teil des Operanden einer Größe von .__ ist. Operator und das Ändern des Werts des Größenausdrucks würde nicht das Ergebnis des Operators beeinflussen, wird nicht angegeben, ob Der Größenausdruck wird ausgewertet.
Zum Beispiel in einem Fall wie diesem (SEHEN SIE ES LIVE):
sizeof( int (*)[x++] )
Da der Operand des Operators sizeof
nicht ausgewertet wird, können Sie Folgendes tun:
int f(); //no definition, which means we cannot call it
int main(void) {
printf("%d", sizeof(f()) ); //no linker error
return 0;
}
Online-Demo: http://ideone.com/S8e2Y
Das heißt, Sie müssen die Funktion f
nicht definieren, wenn sie nur in sizeof
verwendet wird. Diese Technik wird hauptsächlich bei der Metaprogrammierung von C++ - Schablonen verwendet, da der Operand von sizeof
selbst in C++ nicht ausgewertet wird.
Warum funktioniert das? Es funktioniert, weil der Operator sizeof
nicht mit value arbeitet, sondern mit type des Ausdrucks. Wenn Sie also sizeof(f())
schreiben, arbeitet es mit dem type des Ausdrucks f()
, und dies ist nichts anderes als der Rückgabetyp der Funktion f
. Der Rückgabetyp ist immer derselbe, unabhängig davon, welchen Wert die Funktion zurückgeben würde, wenn sie tatsächlich ausgeführt wird.
In C++ können Sie sogar Folgendes tun:
struct A
{
A(); //no definition, which means we cannot create instance!
int f(); //no definition, which means we cannot call it
};
int main() {
std::cout << sizeof(A().f())<< std::endl;
return 0;
}
Es sieht jedoch so aus, als würde ich in sizeof
zuerst eine Instanz von A
erstellen, indem Sie A()
schreiben und dann die Funktion f
in der Instanz aufrufen, indem Sie A().f()
schreiben, aber nichts passiert.
Demo: http://ideone.com/egPMi
Hier ist ein anderes Thema, das einige andere interessante Eigenschaften von sizeof
erklärt:
Die Ausführung kann nicht während des Kompilierens erfolgen. ++i
/i++
wird also nicht vorkommen. Auch sizeof(foo())
führt die Funktion nicht aus, gibt aber den richtigen Typ zurück.
sizeof
wird zur Kompilierzeit ausgeführt, x++
kann jedoch nur zur Laufzeit ausgewertet werden. Um dies zu lösen, schreibt der C++ - Standard vor, dass der Operand von sizeof
nicht ausgewertet wird (mit Ausnahme von VLAs). Der C-Standard sagt:
Wenn der Typ des Operanden [von
sizeof
] ein Array-Typ mit variabler Länge ist, wird der Operand ausgewertet. Andernfalls wird der Operand nicht ausgewertet und das Ergebnis ist eine Ganzzahlkonstante.
Der Operator sizeof()
gibt nur die Größe des Datentyps an, er wertet keine inneren Elemente aus.