Lang lang in c99

Jan 10 2021

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 longja 8, warum muss dann ein weiterer long longTyp hinzugefügt werden? Was macht das mit dem Compiler / der Architektur?

Antworten

6 chux-ReinstateMonica Jan 10 2021 at 05:36

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 longund int32 oder 16 Bit basiert .

Das Erfordernis longals 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 longvon 32-Bit oder 64-Bit (oder anderen) ermöglicht den Übergang.

Verschiedene Funktionen übergeben longwie / zurück wie fseek(), ftell(). Sie profitieren von longmehr 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_tund diesen ptrdiff_tnicht haben sollten, sollten nicht höher sein als der, es signed long intsei 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_t32/64/128/256 Bit verwenden.

IAC, ich sehe Typen mit fester Breite, intN_tdie gegenüber longund immer beliebter werden long long. Ich neige dazu, Typen mit fester Breite oder bool( unsigned) char, int/ unsigned,, size_t( u) zu verwenden intmax_tund signed char( unsigned) short, ( unsigned) long, ( unsigned) long longfür Sonderfälle zu belassen.

4 dbush Jan 10 2021 at 05:26

Der C-Standard garantiert nur, dass a int(lose gesagt) 2 Bytes, a long4 Bytes und a long long8 Bytes sein kann.

Tatsächlich verwendet MSVC immer noch 4 Byte long, obwohl es 4 Byte hat int.

3 NateEldredge Jan 10 2021 at 05:38

Die einzige relevante Anforderung für intund longdamals und heute ist, dass intsie mindestens 16 Bit und longmindestens 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 longund machen sich nicht die Mühe, es long longgröß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.

2 PeterCordes Jan 10 2021 at 10:29

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_MAXund 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 longeine ziemlich vernünftige Wahl.

Kein vernünftiger ABI für einen 32-Bit-Computer wie i386 würde 64-Bit verwenden, longda 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 -m32oder 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 intusw.).

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 longist also wohl nicht so toll , einen 64-Bit-Typ zu erstellen. Einige Codes werden verwendet, longweil sie einen Typ wünschen, der 32-Bit sein muss, aber nicht davon profitiert, dass er breiter ist. Bei einem solchen Code longverschwendet 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 longhofft manchmal, "der breiteste effiziente Typ (1 Register)" zu sein, obwohl es keine solche Garantie gibt und LLP64-ABIs wie Windows x64 mit 32-Bit longnicht so sind.

Eine weitere ganze Dose Würmer ist int_fast32_tdie 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_twirft 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
old_timer Jan 11 2021 at 06:16

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.