Wie funktioniert sizeof(array) zur Laufzeit?

Lesezeit: 6 Minuten

Ich habe gelesen, dass der sizeof-Operator in C zur Kompilierzeit interpretiert wird, und da der Compiler zur Kompilierzeit die Arraygröße und ihren Typ kennt, kann sizeof die Anzahl der vom Array belegten Bytes berechnen. Aber wie funktioniert sizeof für den folgenden Code:

 #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;
 }

Hier ist die Arraygröße zur Kompilierzeit nicht bekannt, wie funktioniert sie dann richtig?

  • mögliches Duplikat von Using sizeof mit einem dynamisch zugewiesenen Array

    – Mattball

    9. April 2012 um 19:06 Uhr

  • Arrays variabler Länge sind für sie eine Ausnahme, sizeof wird zur Laufzeit ausgewertet, nicht zur Kompilierzeit.

    – Daniel Fischer

    9. April 2012 um 19:06 Uhr

  • @ MДΓΓБДLL Nein, das ist ungefähr malloced Zeug, nicht über VLAs.

    – Daniel Fischer

    9. April 2012 um 19:07 Uhr

  • @MДΓΓБДLL: Ihr mögliches Duplikat hat es mit einer anderen Situation zu tun (malloc()kein VLA, Array variabler Länge).

    – Jonathan Leffler

    9. April 2012 um 19:07 Uhr

sizeof wird immer zur Kompilierzeit in C89 berechnet. Seit C99 und Arrays mit variabler Länge wird es zur Laufzeit berechnet, wenn ein Array mit variabler Länge Teil des Ausdrucks in ist sizeof Operand.

Gleiches gilt für die Auswertung der sizeof Operand: Er wird nicht in C89 ausgewertet, aber in C99, wenn der Operand vom Array-Typ variabler Länge ist, wird er ausgewertet. Zum Beispiel:

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

// n is now 6

  • Was bedeutet das int [n++]? Zum ersten Mal sehe ich es in C-Sprache

    – Die Maske

    9. Juni 2013 um 21:45 Uhr

  • @Die Maske int [N] ist ein Name vom Typ C. Es ist ein Array N von int. Wann N ist keine Konstante wie in der Antwort, es ist a Array mit variabler Länge.

    – au

    9. Juni 2013 um 21:49 Uhr

  • @ouah: Wir haben früher untersucht, dass der Ausdruck innerhalb des sizeof-Operators nicht wirklich ausgewertet wird. dh. sizeof(n++) lässt n auf 5 (wenn n=5 anfänglich). Warum wird dann hier der Wert von n geändert?

    – rforritz

    12. Juni 2013 um 21:27 Uhr

  • @rforritz Array-Typ-Operand mit variabler Länge ist eine Ausnahme von dieser Regel, in diesem Fall wird der Operand ausgewertet

    – au

    12. Juni 2013 um 21:33 Uhr

Benutzer-Avatar
zwöl

Da Sie sich bewerben sizeof zu einem Array variabler Länge, dessen Größe zur Kompilierzeit nicht vollständig bekannt ist, muss der Compiler Code generieren, um einen Teil davon zur Laufzeit auszuführen.

Die High-Level-Optimierer von gcc 4.6.3 konvertieren den von Ihnen angezeigten Code

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);

Erklärt das, was unter der Haube vor sich geht? (Lassen Sie sich nicht von der albern aussehenden Anzahl temporärer Variablen abschrecken – das ist ein Artefakt des Programms, in dem es sich befindet statische Einzelzuweisung Formular an der Stelle, an der ich um einen Zwischencode-Dump gebeten habe.)

  • Legen Sie die Datei, die Sie kompilieren möchten, in einem eigenen Verzeichnis ab, rufen Sie dann gcc von einer Shell in diesem Verzeichnis aus auf und fügen Sie hinzu -fdump-tree-all zu den Befehlszeilenoptionen (Sie möchten wahrscheinlich -S und -O2 auch). Sie müssen die Datei in einem Scratch-Verzeichnis isolieren, da dadurch etwa 100 Dateien mit Zwischencode generiert werden (und das ist nur die erste Hälfte der Optimierungspipeline; -fdump-rtl-all erhalten Sie weitere 60 Dateien). Sie können sie dann der Reihe nach durchlesen (sie sind nummeriert)

    – zol

    19. Juni 2013 um 3:02 Uhr

  • @TheMask (Fortsetzung) Die “Baum”-Dumps sind im Allgemeinen nützlicher als die “rtl”-Dumps, es sei denn, Sie versuchen, eines der “Backends” von GCC (Codegenerierung für eine bestimmte Architektur) zu debuggen. Sie können die Ausgabe auf einen bestimmten interessanten Durchgang beschränken, indem Sie sagen -fdump-(tree|rtl)-PASSNAME Anstatt von -all, wobei PASSNAME das Wort nach der Zahl im Dump-Dateinamen ist. Sehen gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/… (etwas nach oben scrollen, dann von dort bis zum Ende des Dokuments lesen) für weitere Details.

    – zol

    19. Juni 2013 um 3:07 Uhr

  • @TheMask … Ich sollte dich wahrscheinlich auch auf das hinweisen Interna-Handbuch für GCC was erklärt, was die Zwischendarstellungen sind und wie sie funktionieren.

    – zol

    19. Juni 2013 um 3:09 Uhr

  • Ich danke dir sehr! Ich werde mir das alles ansehen. 🙂

    – Die Maske

    22. Juni 2013 um 13:14 Uhr

Aus dem C99-Standard:

6.5.3.4

Das sizeof Operator liefert die Größe (in Bytes) seines Operanden, der ein Ausdruck oder der Name eines Typs in Klammern sein kann. Die Größe wird durch den 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 ganzzahlige Konstante.

Benutzer-Avatar
Greg Hewgill

In diesem Fall, sizeof() wird zur Laufzeit ausgewertet. Der Compiler, weil er weiß, dass die Größe von a basiert auf dem Wert von n Generiert zum Zeitpunkt der Array-Deklaration Code, um den entsprechenden Wert von zu verwenden n um einen sinnvollen Wert zurückzugeben sizeof().

In C99 werden nicht alle Verwendungen von sizeof() kann zur Kompilierzeit vollständig ausgewertet und auf eine Laufzeitkonstante reduziert werden.

Ich habe gelesen, dass der sizeof-Operator in C zur Kompilierzeit interpretiert wird

sizeof wird in allen Fällen außer für VLAs zur Kompilierzeit bestimmt. Für ein VLA, sizeof wird zur Laufzeit ausgewertet.

  • Tatsächlich (C11): “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 ganzzahlige Konstante.”

    – pmor

    22. November 2021 um 16:00 Uhr

Benutzer-Avatar
R.. GitHub HÖREN SIE AUF, ICE ZU HELFEN

Egal ob sizeof wird zur Kompilierzeit oder zur Laufzeit berechnet (oder formaler ausgedrückt, ob das Ergebnis ein ganzzahliger konstanter Ausdruck ist), das Ergebnis von sizeof basiert rein auf der Art seiner Argumentation und keine versteckten Daten, die das Array mit variabler Länge selbst begleiten. Natürlich wann sizeof auf einen variabel modifizierten Typ angewendet wird, muss das generierte Programm diese Größe irgendwo verfolgen. Aber es könnte es einfach neu berechnen, wenn der Ausdruck einfach genug wäre und die Variablen, von denen er ursprünglich die Länge abgeleitet hat, sich nicht geändert haben können. Oder es könnte die Größe des Typs irgendwo speichern (im Wesentlichen in einer versteckten lokalen Variablen), aber dies wäre nicht auf sichtbare Weise mit dem VLA-Objekt verbunden (z. B. wenn Sie einen Zeiger auf das erste Element des VLA übergeben zu einer anderen Funktion, kann dieser Zeiger nicht verwendet werden, um die VLA-Länge wiederherzustellen).

  • Tatsächlich (C11): “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 ganzzahlige Konstante.”

    – pmor

    22. November 2021 um 16:00 Uhr

1353160cookie-checkWie funktioniert sizeof(array) zur Laufzeit?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy