Lang lang in c99
Im C99-Standard haben sie eingeführt long long
. Was ist der Zweck davon? In meiner (eingeschränkten) C-Programmiererfahrung habe ich jeweils nur einen 4-Byte-Int und einen 8-Byte-Long gesehen. Zum Beispiel aus dem Compiler Explorer:

Wenn long
ja 8
, warum muss dann ein weiterer long long
Typ hinzugefügt werden? Was macht das mit dem Compiler / der Architektur?
Antworten
Wenn long bereits 8 ist, warum muss dann ein weiterer long long-Typ hinzugefügt werden? Was macht das mit dem Compiler / der Architektur?
"Wenn long schon 8 ist" ist nicht immer wahr, da viel Code existiert, der auf 32-Bit long
und int
32 oder 16 Bit basiert .
Das Erfordernis long
als 64-Bit würde die Codebasen beschädigen . Dies ist ein wichtiges Anliegen.
Das Erfordernis long
, 32-Bit (und Nein long long
) zu bleiben, würde jedoch keinen Zugriff auf Standard-64-Bit-Ganzzahlen ermöglichen, daher eine Begründung für long long
.
Das Zulassen long
von 32-Bit oder 64-Bit (oder anderen) ermöglicht den Übergang.
Verschiedene Funktionen übergeben long
wie / zurück wie fseek(), ftell()
. Sie profitieren von long
mehr als 32-Bit für die Unterstützung großer Dateien.
Die empfohlene Vorgehensweise ermutigt zu einem breiteren long
: "Die Typen, die für einen ganzzahligen Konvertierungsrang verwendet werden size_t
und diesen ptrdiff_t
nicht haben sollten, sollten nicht höher sein als der, es signed long int
sei denn, die Implementierung unterstützt Objekte, die groß genug sind, um dies erforderlich zu machen." Dies bezieht sich auf Speichergrößen von mehr als 32 Bit.
Möglicherweise wird eine Implementierung in Zukunft int/long/long long/intmax_t
32/64/128/256 Bit verwenden.
IAC, ich sehe Typen mit fester Breite, intN_t
die gegenüber long
und immer beliebter werden long long
. Ich neige dazu, Typen mit fester Breite oder bool
( unsigned
) char
, int
/ unsigned
,, size_t
( u
) zu verwenden intmax_t
und signed char
( unsigned
) short
, ( unsigned
) long
, ( unsigned
) long long
für Sonderfälle zu belassen.
Der C-Standard garantiert nur, dass a int
(lose gesagt) 2 Bytes, a long
4 Bytes und a long long
8 Bytes sein kann.
Tatsächlich verwendet MSVC immer noch 4 Byte long
, obwohl es 4 Byte hat int
.
Die einzige relevante Anforderung für int
und long
damals und heute ist, dass int
sie mindestens 16 Bit und long
mindestens 32 Bit betragen muss. 16- und 32-Bit-Systeme verfügen in der Regel über 32-Bit-Systeme long
, und 64-Bit-Computer waren Ende der neunziger Jahre weitaus seltener. Vor C99 konnten sich Programmierer also nicht darauf verlassen, dass überhaupt ein 64-Bit-Integer-Typ verfügbar war. Dieses Problem wurde durch die Einführung von gelöst long long
, die mindestens 64 Bit betragen muss. (Ich glaube, es wurde bereits von GCC und möglicherweise anderen Compilern als Erweiterung bereitgestellt).
Heutzutage verwenden viele (aber nicht alle) 64-Bit-Systeme ein 64-Bit-System long
und machen sich nicht die Mühe, es long long
größer zu machen. Daher ist es auch 64-Bit und in gewissem Sinne redundant. Dies sind vermutlich die Systeme, mit denen Sie vertraut sind, aber sie repräsentieren nicht alles da draußen.
Ich denke, Sie haben nicht bemerkt, dass Sie eine große falsche Annahme darüber machen, wie die Anforderungen an die C- Typbreite funktionieren: ISO C legt nur einen Mindestwertbereich fest, wie die kleinste zulässige Größe LONG_MAX
und LONG_MIN
(-2147483647, nicht 8, weil ISO C. Ermöglicht das Komplement und die Vorzeichen- / Größen-Ganzzahlen mit Vorzeichen, nicht nur das Zweierkomplement.) Tatsächliche Implementierungen dürfen breitere Typen haben, häufig um einer Registerbreite oder Operandengröße zu entsprechen, die die Zielmaschine effizient ausführen kann.
Auf Stack Overflow und anderswo wurde viel darüber geschrieben, was ich hier nicht wiederholen werde. Siehe auchhttps://en.cppreference.com/w/c/language/arithmetic_types
Das hat Sie zu dem Fehler geführt, die Auswahl der Typbreite im x86-64 System V ABI zu betrachten und anzunehmen, dass andere C-Implementierungen gleich sind, denke ich. x86-64 ist eine 64-Bit-ISA, die effizient mit 64-Bit-Ganzzahlen arbeiten kann. Daher war 64-Bit long
eine ziemlich vernünftige Wahl.
Kein vernünftiger ABI für einen 32-Bit-Computer wie i386 würde 64-Bit verwenden, long
da dies nicht erforderlich ist, sondern nur 32-Bit. Die Verwendung von 64-Bit würde bedeuten, dass es nicht in ein einzelnes Register passen könnte. Kompilieren Sie mit -m32
oder kompilieren Sie für 32-Bit-ARM. Godbolt hat auch GCC für AVR und MSP430. Auf diesen 8-Bit- und 16-Bit-Computern wählt GCC die kleinsten nach ISO C zulässigen Breiten aus (2 Byte int
usw.).
1999 gab es x86-64 noch nicht einmal. (Einige andere 64-Bit-ISAs wie Alpha). Wenn Sie sich also eines der beiden gängigen ABIs ansehen, um die C99-Auswahl zu verstehen, werden Sie nicht sehr weit kommen.
Natürlich benötigt C einen Typ, der garantiert mindestens 64-Bit ist, damit die Leute Programme schreiben können, die effizient 64-Bit-Ganzzahlmathematik ausführen.
Übrigens kann x86-64 32-Bit-Integer-Aufgaben genauso effizient ausführen wie 64-Bit, manchmal sogar effizienter. Es long
ist also wohl nicht so toll , einen 64-Bit-Typ zu erstellen. Einige Codes werden verwendet, long
weil sie einen Typ wünschen, der 32-Bit sein muss, aber nicht davon profitiert, dass er breiter ist. Bei einem solchen Code long
verschwendet 64-Bit nur den Cache-Platzbedarf / die Speicherbandbreite und die Codegröße (REX-Präfixe). In C99 wäre die ideale Wahl int_least32_t
, aber das ist ärgerlich lang zu tippen und wird selten verwendet.
Aber OTOH long
hofft manchmal, "der breiteste effiziente Typ (1 Register)" zu sein, obwohl es keine solche Garantie gibt und LLP64-ABIs wie Windows x64 mit 32-Bit long
nicht so sind.
Eine weitere ganze Dose Würmer ist int_fast32_t
die schlechte Wahl von IMO für C99 und x86-64 System V, um daraus einen 64-Bit-Typ zu machen. (Ich habe eine halb geschriebene Antwort für Cpp. Uint32_fast_t wird in uint64_t aufgelöst, ist aber für fast alle Operationen langsamer als uint32_t (x86_64). Warum wird uint64_t aufgelöst? Was ich beenden sollte ... int_fast32_t
wirft die Frage nach "schnell für was" auf Zweck ", und bei vielen Implementierungen ist es nicht das, was Sie für viele Fälle hoffen würden.
Siehe auch
- C ++ - der schnellste Integer-Typ?
- Wie sollen die [u] int_fastN_t-Typen für x86_64 mit oder ohne x32-ABI definiert werden?
- Warum sollte uint32_t gegenüber uint_fast32_t bevorzugt werden?
- Warum ist uint_least16_t für die Multiplikation in x86_64 schneller als uint_fast16_t?
- Compiler-Optimierungen sind über die nicht festen Breitentypen C / C ++ "int", "Least" und "Fast" zulässig
Es gibt einige Einschränkungen, aber der Compilerautor kann die Längen für die Standard-C-Variablentypen (char, short, int, long, long long) frei wählen. Natürlich wird char ein Byte für diese Architektur sein (die meisten mit C-Compilern sind 8 Bit). Und natürlich kann etwas Kleineres nicht größer sein als etwas Größeres, Long kann nicht kleiner sein als ein Int. Aber sicherlich haben wir 1999 den x86 16- bis 32-Bit-Übergang gesehen und zum Beispiel hat sich int mit einer Reihe von Werkzeugen von 16 auf 32 geändert, blieb aber lange 32. Später geschah der 32- bis 64-Bit-x86-Übergang, und je nach Werkzeug waren Typen verfügbar helfen.
Das Problem bestand lange zuvor und die Lösung bestand nicht darin, die Länge der Typen festzulegen, sondern innerhalb der Regeln den Compilerautoren hinsichtlich der Größe zu überlassen. Die Compilerautoren müssen jedoch eine stdint.h-Datei erstellen, die mit dem Tool und dem Ziel übereinstimmt (stdint.h ist mindestens spezifisch für ein Tool und ein Ziel und kann eine Version des Tools und der Build-Optionen für dieses Tool usw. sein). So ist beispielsweise uint32_t immer 32 Bit. Einige Autoren konvertieren das in ein int, andere lange usw. in ihrer stdint.h. Die Variablentypen der C-Sprache bleiben je nach Sprache auf char, short, int usw. beschränkt (uint32_t ist kein Variablentyp, sondern wird über stdint.h in einen Variablentyp konvertiert). Diese Lösung / Problemumgehung war ein Weg, um zu verhindern, dass alles verrückt wird und die Sprache am Leben bleibt.
Autoren wählen beispielsweise häufig aus, ob die GPRs 16 Bit sind, um int 16 Bit zu haben, und wenn 32 Bit 32 Bit sind und so weiter, aber sie haben etwas Freiheit.
Ja, dies bedeutet insbesondere, dass es keinen Grund gibt anzunehmen, dass zwei Tools für ein bestimmtes Ziel (z. B. den Computer, auf dem Sie dies lesen) dieselben Definitionen für int und long verwenden und insbesondere, für die Sie Code schreiben möchten Diese Plattform, die über diese Tools portieren kann (die diese Plattform unterstützen), verwendet dann die Typen stdint.h und nicht int, long usw. Mit Sicherheit, wenn Sie Plattformen überqueren, eine msp430 mcu, eine arm mcu, eine arm linux machine , eine x86-basierte Maschine, bei der die Typen selbst für dieselbe "Toolchain" (z. B. gnu gcc und binutils) nicht dieselben Definitionen für int und long usw. haben. char und short sind in der Regel 8 und 16 Bit. int und long neigen dazu, am meisten zu variieren, manchmal gleich groß, manchmal unterschiedlich, aber der Punkt ist nicht anzunehmen.
Es ist trivial, die Größen für eine Compilerversion / Ziel- / Befehlszeilenoptionen zu ermitteln oder einfach die Standardroute zu wählen, um Probleme später zu minimieren.