2010-08-26 10 views
25

Das mag eine blöde Frage sein, aber wie weiß der sizeof-Operator die Größe eines Array-Operanden, wenn Sie die Anzahl der Elemente im Array nicht übergeben. Ich weiß, dass es nicht die gesamten Elemente im Array zurückgibt, sondern die Größe in Bytes, aber damit es immer noch wissen muss, wann das Array endet. Nur neugierig wie das geht.Wie kennt sizeof die Größe des Operandenarrays?

+0

See: http://stackoverflow.com/questions/492384/how-to-find-the-sizeof-a-pointer-pointing-to-an-array –

+6

+1 für alle diejenigen, die ' sizeof' war ein Kompilierzeitoperator, -1 für alle, die sagten, dass er die Größe des Arrays verfolgt, auf das ein Zeiger zur Laufzeit zeigt. –

+0

Wow! Zehn Antworten, bis ich meine Antwort beendet habe. Ich werde alt ;-) – stacker

Antwort

39

sizeof wird zur Kompilierzeit interpretiert, und der Compiler weiß, wie das Array deklariert wurde (und somit, wie viel Platz es belegt). Das Aufrufen von sizeof auf einem dynamisch zugewiesenen Array wird wahrscheinlich nicht das tun, was Sie wollen, weil (wie Sie erwähnen) der Endpunkt des Arrays nicht spezifiziert ist.

+0

ziemlich sicher, dass dies nicht wahr ist, durch die Diskussion über die Frage selbst, sowie das Lesen der Spezifikation - zumindest für moderne C. Es wäre besser für diese Antwort entfernt werden. http: //en.wikipedia.org/wiki/Sizeof – xaxxon

+2

@xaxxon: Der Standard sagt nicht * explizit *, dass er zur Kompilierzeit ausgewertet wird, aber er sagt, dass 'sizeof' seinen Operanden nicht auswertet. Der Operandenausdruck ist nur für den Compiler von Bedeutung, also ist er wirklich der einzige Ort, an dem er implementiert werden kann. VLAs werden indirekt vom Compiler behandelt. Der Compiler muss bereits Code generieren, um zu berechnen, wie viel Speicherplatz für das VLA zugewiesen werden muss (die Array-Elementgröße * eine Variable), damit er diese Nummer für alle Aufrufe von 'sizeof' auf diesem VLA erneut verwenden kann. – bta

9

Der Compiler kennt die Größe jedes Typs in Ihrer Anwendung, und sizeof fordert nur den Compiler auf, diesen Wert für Sie zu erstellen.

+0

Das ist nicht wahr. Arrays mit variabler Länge werden nicht zur Kompilierzeit abgearbeitet. Sie sollten Ihre Antwort aktualisieren oder entfernen. http://en.wikipedia.org/wiki/Sizeof – xaxxon

+0

@xaxxon: Ab sofort sind Arrays variabler Länge in C++ ungültig, daher lautet die Antwort: Die Größe von * allen gültigen C++ - Typen * wird zur Kompilierzeit berechnet. Arrays mit variabler Länge für C++ wurden dem Komitee in der letzten Sitzung vorgeschlagen, und der Vorschlag wurde gut angenommen, aber das wird C++ nicht gültig sein, bis der nächste Standard (C++ 14) genehmigt wird. Selbst bei VLAs kennt der Compiler * die Größe (er kennt den Ausdruck, aus dem das Array erstellt wurde, so dass er die Nummer beiseite speichern kann), da VLAs den Umfang der Funktion nicht abbilden können wird gebraucht. –

8

Sizeof ist ein Kompilierzeit-Operator; Es enthält so viele Informationen wie der Compiler. (Und offensichtlich der Compiler ist wissen die Größe des Arrays).

Deshalb, wenn Sie sizeof auf einen Zeiger aufrufen, erhalten Sie die Breite des Zeigers, nicht die Größe des Arrays, auf das der Zeiger zeigt.

+0

Also, (nicht C++ seit ein paar Jahren verwendet), was passiert, wenn Sie nach Größe und den Zeiger auf das Array dereferenzieren? Fällt sizeof einfach aus, oder sucht es nach etwas, das über die Größe des Arrays aufgezeichnet wurde und gibt das zurück? –

+2

Wenn Sie den Zeiger dereferenzieren, erhalten Sie einen Verweis auf das Objekt, das das Array gespeichert hat, und sizeof gibt diesen zurück. 'int a [5]; int * p = a; assert (sizeof (* p) == sizeof (int); ' –

+0

Dies ist nicht wahr. Arrays mit variabler Länge werden bei der Kompilierung nicht behandelt. Sie sollten Ihre Antwort aktualisieren oder sie entfernen. http: //en.wikipedia. org/wiki/Sizeof – xaxxon

2

Wenn Sie sizeof für eine lokale Variable verwenden, weiß es, wie viele Elemente Sie deklariert haben. Wenn Sie sizeof für einen Funktionsparameter verwenden, weiß es nicht; Sie behandelt den Parameter als Zeiger auf das Array und sizeof gibt die Größe eines Zeigers an.

+0

Es tut kennt. Der Parameter * ist * ein Zeiger (auf das erste Element, nicht auf das Array) und der Compiler kennt die Größe des Zeigers. C hat keine Array-Parameter. –

12

Außer in einem Fall, sizeof tut es zur Kompilierzeit. Zur Kompilierzeit verfolgt der Compiler den vollen Typ eines Objekts [Edit: Nun, alles, was es über den Typ des Objekts weiß sowieso - wenn der Typ nicht abgeschlossen ist, so dass die Größe nicht enthält Der Versuch, sizeof zu verwenden, wird fehlschlagen], und sizeof "exportiert" im Grunde nur einen Teil dieser Informationen vom Compiler in den zu kompilierenden Code, so dass er im Wesentlichen zu einer Konstante im resultierenden Code wird.

Die Ausnahme ist, wenn sizeof auf variable Länge Array (VLA) angewendet wird. Bei Anwendung auf ein VLA wertet sizeof seinen Operanden aus (was nicht anders ist) und erzeugt die tatsächliche Größe des VLA. In diesem Fall ist das Ergebnis keine Konstante.


1. VLAs wurde offiziell ein Teil von C in C99, aber einige Compiler unterstützt sie davor. Obwohl nicht offiziell Teil von C++, enthalten einige Compiler (z. B. g ++) VLAs als eine Erweiterung von C++.

+3

Der Compiler verfolgt den vollständigen Typ ... es sei denn, dies ist nicht der Fall, weil der Typ unvollständig ist. In diesem Fall kann 'sizeof' nicht verwendet werden. – Potatoswatter

+0

@Potatoswatter: guter Punkt. Geändert, um diese Tatsache widerzuspiegeln. –

+0

Das ist nicht wahr. Arrays mit variabler Länge werden nicht zur Kompilierzeit abgearbeitet. Sie sollten Ihre Antwort aktualisieren oder entfernen. http://en.wikipedia.org/wiki/Sizeof – xaxxon

1

Zitat von wiki:

Es liegt in der Verantwortung des Autors Compiler den sizeof Operator in einer Art und Weise spezifisch und richtig für eine gegebene Implementierung von die Sprache zu implementieren. Der sizeof-Operator muss die Implementierung des zugrundeliegenden Speicherzuordnungsschemas berücksichtigen, um die Größen verschiedener Datentypen zu erhalten.sizeof ist normalerweise ein Kompilieroperator, der bedeutet, dass während der Kompilierung sizeof und sein Operand durch den Result-Wert ersetzt werden. Dies ergibt sich aus dem Assemblersprachcode , der von einem C oder einem C++ - Compiler erzeugt wird. Aus diesem Grund sizeof qualifiziert sich als ein Operator, auch obwohl seine Verwendung manchmal wie ein Funktionsaufruf aussieht.

+2

Obwohl dies zutrifft, beantwortet es die Frage des OP nicht wirklich. –

1

Der sizeof operator ‚weiß‘ die Größe aller atomaren Datentypen, da structs, Gewerkschaften und Arrays nur durch die Montage der Atomtypen konstruiert werden kann, ist es einfach, die Größe des Arrays von jeder Art zu bestimmen. Es verwendet grundlegende Arithmetik, um komplexe Typen zu bestimmen (während der Kompilierungszeit).

4

Sizeof kann nur auf vollständig definierte Typen angewendet werden. Der Compiler ist entweder in der Lage, die Größe zur Kompilierzeit zu bestimmen (zB wenn Sie eine Deklaration wie int foo [8] hatten;), oder er kann bestimmen, dass er Code hinzufügen muss, um die Größe einer Variablen zu verfolgen length array (zB wenn Sie eine Deklaration wie int foo [n + 3];) hatten.

Im Gegensatz zu anderen Antworten hier, beachten Sie, dass ab S99 sizeof() nicht unbedingt zur Kompilierzeit bestimmt, da Arrays variabler Länge sein können.

+0

s/Laufzeit/Kompilierzeit/g und es wird eine gute Antwort. – ninjalj

+0

Derp. Vielen Dank. :-) – ngroot

+0

Über selbsterfüllende Prophezeiungen sprechen :) – ninjalj

19

Das Problem, das Ihrem Problem zugrunde liegt, könnte darin liegen, dass Sie Arrays und Zeiger so verwirren, wie es so viele tun. Arrays sind jedoch keine Zeiger. A double da[10] ist ein Array von zehn double, nicht ein double*, und das ist sicherlich dem Compiler bekannt, wenn Sie es fragen sizeof(da) bewerten. Sie würden nicht überrascht sein, dass der Compiler sizeof(double) kennt?

Das Problem mit Arrays besteht darin, dass sie in vielen Kontexten automatisch auf Zeiger auf ihre ersten Elemente abfallen (wenn sie beispielsweise an Funktionen übergeben werden). Aber Array sind Arrays und Zeiger sind Zeiger.

+2

+1 für die Erklärung der Wurzel des gemeinsamen Missverständnisses hier. –

+0

Absolut richtig, sbi. In den Kapiteln 4, 9 und 10 von Peter van der Lindens hervorragendem Buch "Expert C Programming" wird die Unterscheidung zwischen Zeigern und Arrays sehr gut gemacht. Hölle, Kapitel 4 trägt den Titel "Die schockierende Wahrheit: C Arrays und Zeiger sind nicht das Gleiche", genau wie sbi sagte. Und es widmet 15 Seiten dem Thema. Schau dir das Inhaltsverzeichnis an, insb. CH. 4, 9 & 10: http://books.google.com/books?id=9t5uxP9xHpwC&lpg=PP1&dq=expert%20c%20programming&pg=PR8#v=onepage&q&f=false – Dan

0

sizeof wird zur Kompilierzeit berechnet. Wenn Sie ein dynamisches Array erstellen, erstellen Sie es daher folgendermaßen.

char * array; 
int size; 
//Get size somehow. 
array = malloc(size*(sizeof(char))); 

// jetzt während der Kompilierung weiß der Compiler, dass die Größe der Zeichen. da es sie auf den Speicher ausrichten muss. Zu diesem Zeitpunkt weiß das Betriebssystem, wie viel Größe es zuweisen muss.

variabler Länge Arrays auf der anderen Seite sind auf den Stapel erstellt. Aber jeder malloc zugewiesene Speicher würde auf dem Heap erstellt werden.

0

Sizeof wird immer zur Kompilierzeit ausgewertet. In einem Multi-Pass-Compiler muss der Compiler während der Generierung des Symboltabels die Größe jedes Symbols bestimmen, das für die weitere Generierung von Zwischencode deklariert wurde. Also für alle Größe der Referenzen im Code ersetzt den genauen Wert. Bei der Zwischencodeerzeugungsphase werden alle Operatoren, Anweisungen in den richtigen Zwischencode (ASM/anderes Format) umgewandelt. Schließlich m/c Codegenerierungsstufe konvertiert es in den Maschinencode.

Einige Diskussionen oben wr.t die dynamischen Zuordnungen in Bezug auf sizeof gesehen wird nicht im Kontext überhaupt. Irgendein Verweis auf Größe (* p), wobei p ein Zeiger irgendeines Datentyps ist, findet der Compiler nur den Datentyp von * p und ersetzt seine Größe, nicht gehen, um den MCB-Header des zugewiesenen Blocks zu überprüfen, um zu sehen, was zugewiesen ist Speichergröße. Es ist nicht zur Laufzeit.Zum Beispiel double * p; sizeof (* p) kann immer noch ausgeführt werden, ohne Speicher für Zeiger p zuzuweisen. Wie ist es möglich?

+0

"Sizeof wird immer zur Kompilierzeit ausgewertet." Dies gilt nicht für Arrays variabler Länge, wie in anderen Antworten und Fragekommentaren erläutert. Diese Antwort sollte entfernt werden und ist falsch für die aktuelle C-Sprache (lesen Sie die Spezifikation). http://en.wikipedia.org/wiki/Sizeof – xaxxon

1

sizeof ist in der Regel zur Kompilierzeit ausgewertet. Die bemerkenswerte Ausnahme sind C99-Arrays mit variabler Länge.

int main(int argc, char **argv) 
{ 
    if (argc > 1) 
    { 
     int count = atoi(argv[1]); 
     int someArray[count]; 

     printf("The size is %zu bytes\n", sizeof someArray); 
    } 
    else puts("No"); 
} 
Verwandte Themen