it-swarm.com.de

Wer entscheidet über die Größe eines Datentyps oder einer Datenstruktur (abhängig von 32 Bit oder 64 Bit)?

Wer entscheidet über die Größe eines Datentyps oder einer Struktur (abhängig von 32 Bit oder 64 Bit)? Der Compiler oder der Prozessor? Zum Beispiel ist sizeof(int) 4 Bytes für ein 32-Bit-System, während es 8 Bytes für ein 64-Bit-System ist.

Ich habe auch gelesen, dass sizeof(int) bei der Kompilierung mit sowohl 32-Bit als auch 64-Bit Compiler 4 Byte beträgt.

Angenommen, meine CPU kann sowohl 32-Bit- als auch 64-Bit-Anwendungen ausführen. Wer spielt die Hauptrolle bei der Entscheidung über die Datengröße der Compiler oder der Prozessor?

44
Vishal-Lia

Es ist letztendlich der Compiler. Die Compiler-Implementierer können entscheiden, welche Ganzzahlgröße sie für richtig halten, unabhängig davon, mit welcher CPU sie am effizientesten umgehen. Der C (und C++) Standard ist jedoch so geschrieben, dass der Compiler-Implementierer den schnellsten und effizientesten Weg frei wählen kann. Für viele Compiler haben sich die Implementierer dafür entschieden, int als 32-Bit-Wert beizubehalten, obwohl die CPU 64-Bit-Ints von Haus aus sehr effizient verarbeitet.

Ich denke, dies wurde teilweise getan, um die Portabilität zu Programmen zu erhöhen, die geschrieben wurden, als 32-Bit-Maschinen am häufigsten waren und die erwarteten, dass ein int 32-Bit und nicht länger ist. (Es könnte auch sein, dass als Benutzer ser3386109 weist darauf hin , dass 32-Bit-Daten bevorzugt wurden, weil sie weniger Speicherplatz beanspruchen und daher schneller zugegriffen werden können.)

Wenn Sie also sicherstellen möchten, dass Sie 64-Bit-Ints erhalten, verwenden Sie int64_t anstelle von int, um Ihre Variable zu deklarieren. Wenn Sie wissen, dass Ihr Wert in 32 Bit passt, oder wenn Sie sich nicht für die Größe interessieren, verwenden Sie int, damit der Compiler die effizienteste Darstellung auswählt.

Die anderen Datentypen wie struct setzen sich aus den Basistypen wie int zusammen.

43
Prof. Falken

Es ist weder die CPU noch der Compiler oder das Betriebssystem. Es ist alles drei gleichzeitig.

Der Compiler kann nicht einfach Dinge erfinden. Es muss sich an das richtige ABI halten, das das Betriebssystem bereitstellt. Wenn Strukturen und Systemaufrufe, die vom Betriebssystem bereitgestellt werden, Typen mit bestimmten Größen und Ausrichtungsanforderungen aufweisen, kann der Compiler seine eigene Realität nur dann erstellen, wenn die Compilerentwickler Wrapperfunktionen für alles, was das Betriebssystem bereitstellt, erneut implementieren möchten. Dann kann die ABI des Betriebssystems nicht vollständig erstellt werden, sondern muss das tun, was auf der CPU vernünftigerweise möglich ist. Und sehr oft ist die ABI eines Betriebssystems anderen ABIs für andere Betriebssysteme auf derselben CPU sehr ähnlich, da es einfacher ist, die von ihnen geleistete Arbeit wiederzuverwenden (unter anderem für Compiler).

Bei Computern, die sowohl 32-Bit- als auch 64-Bit-Code unterstützen, muss das Betriebssystem noch arbeiten, um die Ausführung von Programmen in beiden Modi zu unterstützen (da das System zwei verschiedene ABIs bereitstellen muss). Einige Betriebssysteme machen das nicht und bei denen haben Sie keine Wahl.

[1] ABI steht für Application Binary Interface. Dies sind Regeln für die Interaktion eines Programms mit dem Betriebssystem. Es definiert, wie ein Programm auf der Festplatte gespeichert wird, damit es vom Betriebssystem ausgeführt werden kann, wie Systemaufrufe ausgeführt werden, wie eine Verknüpfung mit Bibliotheken hergestellt wird usw. Um jedoch beispielsweise eine Verknüpfung mit Bibliotheken herstellen zu können, müssen Programm und Bibliothek übereinstimmen Informationen zum Ausführen von Funktionsaufrufen zwischen Ihrem Programm und der Bibliothek (und umgekehrt) und zum Ausführen von Funktionsaufrufen müssen sowohl das Programm als auch die Bibliothek die gleiche Vorstellung von Stapelaufbau, Registerverwendung, Funktionsaufrufkonventionen usw. haben. Und für Funktionsaufrufe müssen Sie sich darauf einigen, was die Parameter bedeuten und was Größe, Ausrichtung und Vorzeichen von Typen umfasst.

26
Art

Es ist streng genommen 100%, ganz und gar der Compiler, der den Wert von sizeof (int) bestimmt. Es ist keine Kombination aus System und Compiler. Es ist nur der Compiler (und die C/C++ - Sprachspezifikationen).

Wenn Sie iPad- oder iPhone-Apps entwickeln, wird der Compiler auf Ihrem Mac ausgeführt. Der Mac und das iPhone/iPac verwenden unterschiedliche Prozessoren. Nichts über Ihren Mac sagt dem Compiler, welche Größe für int auf dem iPad verwendet werden soll.

8
user3344003

Der Prozessorkonstrukteur bestimmt, welche Register und Anweisungen verfügbar sind, welche Ausrichtungsregeln für einen effizienten Zugriff gelten, wie groß die Speicheradressen sind und so weiter.

Der C-Standard legt Mindestanforderungen für die eingebauten Typen fest. "char" muss mindestens 8 Bit sein, "short" und "int" müssen mindestens 16 Bit sein, "long" muss mindestens 32 Bit sein und "long long" muss mindestens 64 Bit sein. Es heißt auch, dass "char" der kleinsten Speichereinheit entsprechen muss, die das Programm adressieren kann, und dass die Größenreihenfolge der Standardtypen eingehalten werden muss.

Andere Standards können ebenfalls Auswirkungen haben. Beispielsweise besagt Version 2 der "Single Unix Specification", dass int mindestens 32-Bit sein muss.

Schließlich wirkt sich bestehender Code aus. Portierung ist schon schwer genug, niemand will es schwerer machen als nötig.


Beim Portieren eines Betriebssystems und eines Compilers auf eine neue CPU muss jemand das so genannte "C ABI" definieren. Dies definiert, wie Binärcode miteinander kommuniziert, einschließlich.

  • Die Größen- und Ausrichtungsanforderungen der integrierten Typen.
  • Die Verpackungsregeln für Strukturen (und damit, wie groß sie sein werden).
  • Wie Parameter übergeben und zurückgegeben werden
  • Wie wird der Stack verwaltet?

Im Allgemeinen einmal und ABI ist für eine Kombination aus CPU-Familie und Betriebssystem definiert, es ändert sich nicht viel (manchmal ändert sich die Größe von dunkeleren Typen wie "long double"). Ändern bringt eine Menge Bruch für relativ wenig Gewinn.

In ähnlicher Weise wählen diejenigen, die ein Betriebssystem auf eine Plattform portieren, die ähnliche Merkmale wie ein vorhandenes aufweist, normalerweise die gleichen Größen wie auf früheren Plattformen, auf die das Betriebssystem portiert wurde.


In der Praxis entscheiden sich Hersteller von Betriebssystemen/Compilern normalerweise für eine der wenigen Größenkombinationen für die grundlegenden Ganzzahltypen.

  • "LP32": char ist 8 Bits. short und int sind 16 Bit, long und pointer sind 32 Bit. Wird häufig auf 8-Bit- und 16-Bit-Plattformen verwendet.
  • "ILP32": char ist 8 Bit, short ist 16 Bit. int, long und pointer sind alle 32 Bits. Wenn long long existiert, ist es 64 bit. Wird häufig auf 32-Bit-Plattformen verwendet.
  • "LLP64": char ist 8 Bit. Kurz ist 16 Bits. int und long sind 32 Bits. Long Long und Pointer sind 64 Bit. Wird für 64-Bit-Fenster verwendet.
  • "LP64": char ist 8 Bits. Kurz ist 16 Bits. int ist 32 Bits. long, long long und pointer sind 64 Bit. Wird auf den meisten 64-Bit-Unix-ähnlichen Systemen verwendet.
  • "ILP64": char ist 8 Bit, short ist 16 Bit, int, long und pointer und long long sind alle 64 Bit. Wird anscheinend auf einigen frühen 64-Bit-Betriebssystemen verwendet, wird aber heutzutage nur noch selten verwendet.

64-Bit-Prozessoren können normalerweise sowohl 32-Bit- als auch 64-Bit-Binärdateien ausführen. Im Allgemeinen wird dies durch eine Kompatibilitätsebene in Ihrem Betriebssystem erledigt. Ihre 32-Bit-Binärdatei verwendet also dieselben Datentypen wie auf einem 32-Bit-System. Dann übersetzt die Kompatibilitätsebene die Systemaufrufe, sodass das 64-Bit-Betriebssystem sie verarbeiten kann.

5
plugwash

Der Compiler entscheidet, wie groß die Basistypen sind und wie das Layout der Strukturen ist. Wenn eine Bibliothek Typen deklariert, entscheidet sie, wie diese definiert sind und welche Größe sie haben.

Es kommt jedoch häufig vor, dass die Kompatibilität mit einem vorhandenen Standard und die Notwendigkeit der Verknüpfung mit vorhandenen Bibliotheken, die von anderen Compilern erstellt wurden, eine bestimmte Implementierung dazu zwingt, bestimmte Entscheidungen zu treffen. Zum Beispiel besagt der Sprachstandard, dass ein wchar_t Breiter als 16 Bit sein muss und unter Linux 32 Bit breit ist, unter Windows jedoch immer 16 Bit, so dass alle Compiler für Windows dies vorziehen Kompatibel mit der Windows-API anstelle des Sprachstandards. Viele ältere Codes für Linux und Windows setzen voraus, dass ein long genau 32 Bit breit ist, während andere Codes davon ausgehen, dass es breit genug ist, um einen Zeitstempel in Sekunden oder eine IPv4-Adresse oder einen Datei-Offset oder die Bits zu speichern eines Zeigers und (nachdem ein Compiler int als 64 Bit breit und long als 32 Bit breit definiert hat) hat der Sprachstandard eine neue Regel aufgestellt, dass int nicht breiter sein darf als long.

Infolgedessen definieren Mainstream-Compiler aus diesem Jahrhundert int als 32 Bit breit, aber in der Vergangenheit haben es einige als 16 Bit, 18 Bit, 32 Bit, 64 Bit und andere Größen definiert. Bei einigen Compilern können Sie auswählen, ob long genau 32 Bit breit sein soll, wie dies bei einigen Legacy-Codes der Fall ist, oder so breit wie ein Zeiger, wie es bei anderen Legacy-Codes der Fall ist.

Dies zeigt, wie Annahmen, die Sie heute machen, wie ein Typ, der immer 32 Bit breit ist, Sie in Zukunft möglicherweise wieder beißen. Dies war bereits zweimal bei C-Codebasen der Fall, bei den Übergängen zu 32-Bit- und 64-Bit-Code.

Aber was solltest du eigentlich benutzen?

Der Typ int ist heutzutage selten nützlich. In der Regel können Sie einen anderen Typ verwenden, der eine stärkere Garantie für das bietet, was Sie erhalten. (Es hat einen Vorteil: Typen, die nicht so breit sind wie ein int, können automatisch auf int erweitert werden, was zu einigen wirklich seltsamen Fehlern führen kann, wenn Sie signierte und nicht signierte Typen mischen.) und int ist der kleinste Typ, der garantiert nicht kürzer als int ist.)

Wenn Sie eine bestimmte API verwenden, möchten Sie im Allgemeinen den gleichen Typ verwenden, den sie verwendet. In der Standardbibliothek gibt es zahlreiche Typen für bestimmte Zwecke, z. B. clock_t Für Zeitmarken und time_t Für die Zeit in Sekunden.

Wenn Sie den schnellsten Typ mit einer Breite von mindestens 16 Bit verwenden möchten, ist dies int_fast16_t. Es gibt auch andere ähnliche Typen. (Sofern nicht anders angegeben, sind alle diese Typen in <stdint.h> Definiert.) Wenn Sie möchten, dass der kleinste Typ mit einer Breite von mindestens 32 Bit die meisten Daten in Ihre Arrays packt, ist dies int_least32_t. Wenn Sie einen möglichst breiten Typ wünschen, ist dies intmax_t. Wenn Sie wissen, dass Sie genau 32 Bit wollen, nd Ihr Compiler hat einen solchen Typ, ist es int32_t Wenn Sie etwas wollen, das 32 Bit auf einer 32-Bit-Maschine und 64 Bit breit ist Auf einem 64-Bit-Computer und immer in der richtigen Größe, um einen Zeiger zu speichern, ist das intptr_t. Wenn Sie einen guten Typ für die Array-Indizierung und Zeiger-Mathematik suchen, ist dies ptrdiff_t Von <stddef.h>. (Diese steht in einem anderen Header, da sie von C89 und nicht von C99 stammt.)

Verwenden Sie den Typ, den Sie wirklich meinen!

3
Davislor

Wenn Sie über den Compiler sprechen, haben Sie ein sauberes Bild über build|Host|target, Dh die Maschine, auf der Sie bauen (Build), die Maschine, für die Sie bauen (Host), und die Maschine, die GCC erstellt Produziere Code für (Ziel), weil "Cross Compiling" sich sehr von "Native Compiling" unterscheidet.

Bei der Frage "Wer entscheidet über die Größe des Datentyps und der Struktur?" Hängt es vom Zielsystem ab, für das der Compiler Binärdateien erstellen soll. Wenn das Ziel 64 Bit ist, übersetzt der Compiler sizeof (long) in 8, und wenn das Ziel ein 32-Bit-Computer ist, übersetzt der Compiler sizeof (long) in 4. All dies wurde durch die Header-Datei vordefiniert, die Sie zum Erstellen verwendet haben Ihr Programm. Wenn Sie Ihre $ MAKETOP/usr/include/stdint.h lesen, gibt es typedefs, um die Größe Ihres Datentyps zu definieren.

Um den durch den Größenunterschied verursachten Fehler zu vermeiden, empfehlen Google Coding Style-Integer_Types die Verwendung von Typen wie int16_t, uint32_t, int64_t usw. Diese wurden in <stdint.h>.

Oben sind nur die `Plain Old Data ', wie z. B. int. Wenn Sie über eine Struktur sprechen, gibt es eine andere Geschichte, da die Größe einer Struktur von der Packungsausrichtung und der Grenzausrichtung für jedes Feld in der Struktur abhängt , was sich auf die Größe der Struktur auswirkt.

0
gzh

Es ist der Compiler und genauer seine Codegeneratorkomponente.

Natürlich ist der Compiler architekturbewusst und trifft die passenden Entscheidungen.

In einigen Fällen wird die Arbeit in zwei Durchläufen ausgeführt, einer zur Kompilierungszeit von einem Zwischencodegenerator und einer zur Laufzeit von einem Just-in-Time-Compiler. Dies ist jedoch immer noch ein Compiler.

0
Yves Daoust