webentwicklung-frage-antwort-db.com.de

Warum erhöht sizeof (x ++) x nicht?

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?

481
Neigyl R. Noval

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.

511
pmg

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.

183
codaddict

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.

47
sarnold

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
33
hugomg

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.4Der 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.2Array-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.2Array-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++] )
19
Shafik Yaghmour

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:

10
Nawaz

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.

10
rakesh

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.

0
stackptr

Der Operator sizeof() gibt nur die Größe des Datentyps an, er wertet keine inneren Elemente aus.

0
munna