Warum tippt jeder über Standard-C-Typen?

103

Wenn Sie verwenden möchten , Qt , müssen Sie umarmen quint8, quint16und so weiter.

Wenn Sie verwenden möchten GLib , müssen Sie willkommen guint8, guint16und so weiter.

Auf Linux gibt es u32, s16und so weiter.

uC / OS definiert SINT32, UINT16und so weiter.

Und wenn Sie eine Kombination dieser Dinge verwenden müssen, sollten Sie besser auf Probleme vorbereitet sein. Da auf Ihrem Rechner u32werden typedefd über longund quint32wird typedefd über intund der Compiler wird sich beschweren .

Warum macht das jeder, wenn es das gibt <stdint.h>? Ist das eine Art Tradition für Bibliotheken?

Amomum
quelle
8
@Mehrdad in der Mikrocontroller-Programmierung können Sie alle möglichen Dinge haben. Bei AVR Mega zum Beispiel (und folglich bei dem berühmten Arduino) ist int 16 Bit. Das kann eine böse Überraschung sein. Meiner Meinung nach erfordert "unsigned short" mehr Schreibaufwand. Und es hat mich immer traurig gemacht, 'unsigned char' für <s> Byte </ s> Oktett zu verwenden. Charakter ohne Vorzeichen, wirklich?
Amomum
2
@Mehrdad Der Punkt ist, dass Sie nicht wirklich sicher sein können. Genau deshalb stdint.hwurde erfunden.
glglgl
1
@glglgl: Hier ist eine andere Möglichkeit, das Problem zu betrachten: Stellen Sie nicht genau die falsche Frage? Wenn Sie auf mehrere Systeme abzielen, warum sollten Sie die Anzahl der Bits im Code zunächst willkürlich fest codieren? dh warum nicht einfach sizeof(int) * CHAR_BIT(zum Beispiel) sagen und das benutzen? Wenn Ihr intzu klein ist, um Ihren Bereich darzustellen (z. B. ein Array-Index), sollten Sie ihn mit ziemlicher Sicherheit intsowieso nicht verwenden , sondern so etwas size_t. Warum sollte int32es mehr Sinn machen? Die einzige Zeit, in der eine feste Breite sinnvoll ist, ist für die Kommunikation zwischen Systemen (z. B. Datei- / Netzwerkformat) ...
user541686
1
@Mehrdad Nein. Manchmal habe ich Werte (z. B. von einem ADC oder was auch immer), die ich speichern muss. Ich weiß, dass sie 16 Bit breit sind. Das beste Ting ist also uint16_t(oder vielleicht seine fastoder eine leastVariante). Mein Punkt ist: Diese Typen sind bequem zu verwenden und haben ihren Existenzgrund.
glglgl
1
@Mehrdad: Ich würde vorschlagen, dass Sie - vorausgesetzt, es lohnt sich, Qualitätscode zu erstellen - Ihre eigenen funktionalen Typedefs definieren, dh die Art und Weise, wie Sie mit meiner API / dem Rest meines Codes interagieren , und diese aus technischen Gründen in Bezug auf definieren "Technische" typedefs wie size_tund / oder uint64_t.
PJTraill

Antworten:

80

stdint.hexistierte nicht, als diese Bibliotheken entwickelt wurden. Also hat jede Bibliothek ihre eigenen typedefs gemacht.

Edward Karak
quelle
4
Und okay, ich nehme an, das Fehlen von stdint.h ist ein guter Grund, aber warum sind diese typedefs auch heute noch über int, long und so für und nicht über stdint-Typen? Es würde sie mindestens austauschbar machen
Amomum
25
@Amomum "Warum hat Glib (das unter Linux entwickelt wurde) keine Linux-Typedefs verwendet?" Während die "Home Base" von glib sicherlich Linux ist, ist es ebenso sicher eine tragbare Bibliothek. Das Definieren eigener Typen stellt die Portabilität sicher: Es muss nur ein winziger Header angepasst werden, der die Bibliothekstypen an die entsprechenden Zielplattformtypen anpasst.
Peter - Stellen Sie Monica
3
@ Amomum Warum Glib (das wurde unter Linux entwickelt) ... Nein, das war es nicht. Glib wurde erstellt Art und Weise vor dem Linux - Kernel.
andy256
5
@ andy256 "GLib" ist nicht die Abkürzung für "glibc". Es ist eine Bibliothek, die von gtk abgezweigt ist. Es ist nicht älter als Linux.
2
@ andy256: glib ist 1998, linux ist 1991. IOW, GLib wurde weit nach Linux erstellt.
MSalters
40

Für die älteren Bibliotheken ist dies erforderlich, da der betreffende Header ( stdint.h) nicht vorhanden war.

Es gibt jedoch immer noch ein Problem: Diese Typen ( uint64_tund andere) sind eine optionale Funktion im Standard. Eine konforme Implementierung wird daher möglicherweise nicht mitgeliefert - und zwingt die Bibliotheken daher, sie auch heute noch einzuschließen.

Ven
quelle
14
Die uintN_tTypen sind optional, aber die uint_leastN_tund uint_fastN_tTypen nicht.
Kusalananda
7
@Kusalananda: Leider sind diese von begrenztem Nutzen.
Leichtigkeitsrennen im Orbit
16
Verlauf der Grund , dass sie optional sind , ist , dass Sie nicht garantiert werden , dass es sind Integer - Typen mit genau dieser Anzahl von Bits. C unterstützt weiterhin Architekturen mit ziemlich ungeraden Ganzzahlgrößen.
Celtschk
5
@LightnessRacesinOrbit: Wie sind sie von begrenztem Nutzen? Ich muss zugeben, dass ich, abgesehen von Hardware-Schnittstellen, nicht verstehe, warum Sie eine genaue Anzahl von Bits und nicht nur ein Minimum benötigen würden, um sicherzustellen, dass alle Ihre Werte passen.
Celtschk
23
@Amomum Die typedefs sind erforderlich, wenn die Implementierung Typen hat, die die Anforderungen erfüllen: "Wenn eine Implementierung jedoch ganzzahlige Typen mit Breiten von 8, 16, 32 oder 64 Bit, keine Auffüllbits und (für die vorzeichenbehafteten Typen) diese aufweist Bei einer Zweierkomplementdarstellung werden die entsprechenden Typedef-Namen definiert. " (Zitat aus N1570, 7.20.1.1 "Integer-Typen mit exakter Breite") Wenn die Standardbibliothek sie nicht hat, kann es anscheinend auch eine Bibliothek eines Drittanbieters nicht.
Eric M Schmidt
13

stdint.h ist wahrscheinlicher seit 1999. Es ist wahrscheinlicher, dass viele Anwendungen (effektiv Alias-) Typen definieren, um eine teilweise Unabhängigkeit von der zugrunde liegenden Maschinenarchitektur aufrechtzuerhalten.

Sie geben Entwicklern die Gewissheit, dass die in ihrer Anwendung verwendeten Typen ihren projektspezifischen Verhaltensannahmen entsprechen, die möglicherweise weder dem Sprachstandard noch der Compiler-Implementierung entsprechen.

Die Praxis spiegelt sich in der objektorientierten Fassade wider und wird von Entwicklern, die ausnahmslos Wrapper-Klassen für alle importierten Bibliotheken schreiben, häufig missbraucht.

Wenn Complier viel weniger Standard waren und Maschinenarchitekturen von 16-Bit-, 18-Bit- bis 36-Bit- Mainframes mit Wortlänge variieren konnten, war dies eine viel größere Überlegung. In einer Welt, die auf eingebetteten 32-Bit-ARM-Systemen konvergiert, ist diese Praxis jetzt viel weniger relevant. Es bleibt ein Problem für Low-End-Mikrocontroller mit ungeraden Speicherkarten.

Pekka
quelle
1
Zugegeben, stdint.hist seit 1999 standardisiert, aber wie lange ist es in der Praxis verfügbar? Die Menschen ziehen ihre Füße hoch, um neue Standards umzusetzen und zu übernehmen, und während dieser langen Übergangszeit sind alte Methoden immer noch ein Muss.
Siyuan Ren
1
Eine böse Gotcha mit stdint.hist , dass auch auf Plattformen , auf denen beispielsweise longund int32_thaben die gleiche Größe und Darstellung, es gibt keine Anforderung , dass ein Casting int32_t*auf long*einen Zeiger wird erhalten , die zuverlässig ein Zugriff int32_t. Ich kann nicht glauben, dass die Autoren des Standards es für offensichtlich hielten, dass layoutkompatible Typen aliaskompatibel sein sollten, aber da sie sich nicht die Mühe machten, dies zu sagen, glauben die Autoren von gcc und IIRC clang, dass die Sprache verbessert werden würde, indem sie sogar Aliasing ignorieren in Fällen, in denen es offensichtlich ist.
Supercat
2
@supercat - das ist wahrscheinlich wert, als Erratum an das C-Komitee zu
senden
@LThode: Damit das C-Komitee anerkennt, dass es als Fehler erforderlich ist, dass es das Verhalten von clang und gcc offiziell als stumpf deklariert. Glaubst du, dass das passieren wird? Das Beste, was erhofft werden könnte (und meiner Meinung nach die logische Vorgehensweise), wäre, Möglichkeiten für Programme zu definieren, um "Aliasing-Modi" anzugeben. Wenn ein Programm angibt, dass es sehr strenge Aliasing-Regeln akzeptieren kann, kann ein Compiler dies verwenden, um Optimierungen zu ermöglichen, die über das derzeit Mögliche hinausgehen. Wenn ein Programm angibt, dass es Regeln erfordert, die etwas programmiererfreundlicher sind als die gegenwärtigen ...
Supercat
... aber würde immer noch viele nützliche Optimierungen ermöglichen, dann könnte ein Compiler Code generieren, der viel effizienter ist als es mit möglich wäre -fno-strict-alias, der aber tatsächlich noch funktioniert. Selbst wenn keine Codebasis vorhanden wäre, könnte kein einziger Regelsatz das optimale Gleichgewicht zwischen Optimierung und Semantik für alle Anwendungen erzielen, da unterschiedliche Anwendungen unterschiedliche Anforderungen haben. Fügen Sie die vorhandene Codebasis hinzu, und die Notwendigkeit für verschiedene Modi sollte klar sein.
Supercat
3

Sie haben also die Möglichkeit, char in int zu tippen.

Ein "Coding Horror" erwähnte, dass der Header eines Unternehmens einen Punkt hatte, an dem ein Programmierer einen booleschen Wert wollte, und ein Zeichen der logische native Typ für den Job war, und schrieb dies typedef bool char. Später fand jemand eine ganze Zahl als die logischste Wahl und schrieb typedef bool int. Das Ergebnis, das vor Unicode lag, war praktisch typedef char int.

Sehr viel vorausschauendes Denken und Vorwärtskompatibilität, denke ich.

Christos Hayward
quelle