Gründe für die Verwendung (oder Nichtverwendung) von stdint

Lesezeit: 8 Minuten

Benutzeravatar von Sassa
Sassa

Das weiß ich schon stdint wird verwendet, wenn Sie bestimmte variable Größen für die Portabilität zwischen Plattformen benötigen. Ich habe im Moment kein solches Problem, aber was sind die Vor- und Nachteile der Verwendung neben der bereits oben gezeigten Tatsache?

Als ich auf Stackoverflow und anderen Websites danach suchte, fand ich 2 Links, die sich mit dem Thema befassen:

  • codealias.info – dieser spricht über die Portabilität der stdint.

  • Stackoverflow – dieser ist spezifischer uint8_t.

Diese beiden Links sind großartig, besonders wenn man mehr über den Hauptgrund dieses Headers erfahren möchte – Portabilität. Aber was ich am meisten daran mag, ist, dass ich denke uint8_t ist sauberer als unsigned char (z. B. zum Speichern eines RBG-Kanalwerts), int32_t sieht sinnvoller aus als einfach intetc.

Meine Frage ist also, was genau die Vor- und Nachteile der Verwendung sind stdint außer der Tragbarkeit? Soll ich es nur in bestimmten Teilen meines Codes oder überall verwenden? wenn überall, wie kann ich Funktionen wie verwenden atoi(), strtok()usw. damit?

Vielen Dank!

Benutzeravatar von Lundin
Lundin

Vorteile

Die Verwendung gut definierter Typen macht das Portieren des Codes viel einfacher und sicherer, da Sie keine Überraschungen erleben, wenn beispielsweise eine Maschine interpretiert int als 16-Bit und eine andere als 32-Bit. Bei stdint.h erhalten Sie, was Sie eingeben.

Verwenden int usw. macht es auch schwierig, gefährliche Werbeaktionen zu erkennen.

Ein weiterer Vorteil ist, dass durch die Verwendung int8_t Anstatt von charwissen Sie, dass Sie immer eine vorzeichenbehaftete 8-Bit-Variable erhalten. char kann signiert oder unsigniert sein, es handelt sich um ein implementierungsdefiniertes Verhalten und variiert zwischen den Compilern. Daher die Vorgabe char ist einfach gefährlich in Code zu verwenden, der portabel sein sollte.

Wenn Sie dem Compiler Hinweise geben möchten, dass eine Variable optimiert werden sollte, können Sie die verwenden uint_fastx_t Dies weist den Compiler an, den schnellstmöglichen Integer-Typ zu verwenden, der mindestens so groß wie ‘x’ ist. Meistens spielt dies keine Rolle, der Compiler ist intelligent genug, um Optimierungen an Typgrößen vorzunehmen, egal was Sie eingegeben haben. Zwischen Sequenzpunkten kann der Compiler den Typ implizit in einen anderen als den angegebenen ändern, solange dies der Fall ist beeinflusst das Ergebnis nicht.

Nachteile

Keiner.


Referenz: MISRA-C:2004 Regel 6.3.”Typdefs die Größe und Vorzeichen angeben, sind anstelle der Grundtypen zu verwenden”.

BEARBEITEN : Falsches Beispiel entfernt.

  • Offensichtliche Nachteile, wie Wallyk feststellte, sind die Auswirkungen auf die Leistung. Das Zählen von uint32_t-Ganzzahlen auf einem 12-Bit-Computer zu erzwingen, ist mühsam

    – Hroptatyr

    23. März 2012 um 10:40 Uhr

  • uint32_t kann auf einem 12-Bit-Rechner nicht existieren.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    23. März 2012 um 12:02 Uhr

  • @hroptatyr Wenn Sie meine Antwort noch einmal lesen, werden Sie feststellen, dass ich genau dieses Problem angesprochen habe. Wenn es sein muss uint32_t, erkläre es so. Wenn es nicht diese hohe Auflösung braucht, sondern nur 16 Bit, dann deklariere es als uint_fast16_tdie als 32-Bit-Datei auf einer CPU kompiliert wird, bei der die 32-Bit-Ausrichtung schneller ist.

    – Ludin

    23. März 2012 um 12:24 Uhr


  • Gemäß 6.3.1.3 (1), „Wenn ein Wert mit Integer-Typ in einen anderen Integer-Typ außer _Bool konvertiert wird und der Wert durch den neuen Typ dargestellt werden kann, bleibt er unverändert.“ Ihr Beispiel sollte „x > y” auch auf einem 16-Bit-System. Der ganzzahlige Conversion-Rang von long ist größer als die von (unsigned) int, ~x ist UINT_MAXmit 16-bit unsigned ints, 65535, das als a darstellbar ist long. Der Vergleich ist also 65535L > 0L. Der Punkt ist gültig, aber Sie haben ein falsches Beispiel ausgewählt.

    – Daniel Fischer

    27. April 2012 um 22:03 Uhr

  • Entschuldigen Sie die Störung, aber ich möchte wirklich, dass Sie entweder das Beispiel ändern, damit ich positiv stimmen kann, oder auf einen Fehler in meiner Argumentation hinweisen, damit ich positiv stimmen kann.

    – Daniel Fischer

    20. Mai 2012 um 1:12 Uhr

Der einzige Grund zu verwenden uint8_t statt unsigned char (abgesehen von ästhetischen Vorlieben) ist, wenn Sie dokumentieren möchten, was Ihr Programm erfordert char genau 8 Bit sein. uint8_t existiert genau dann, wenn CHAR_BIT==8gemäß den Anforderungen der C-Norm.

Der Rest des intX_t und uintX_t Typen sind in den folgenden Situationen nützlich:

  • Lesen/Schreiben von Festplatte/Netzwerk (aber dann müssen Sie auch Endian-Konvertierungsfunktionen verwenden)
  • wenn Sie ein unsigniertes Wraparound-Verhalten an einem genauen Cutoff wünschen (dies kann jedoch mit der & Operator).
  • wenn Sie das genaue Layout einer Struktur steuern, weil Sie sicherstellen müssen, dass keine Auffüllung vorhanden ist (z memcmp oder Hash-Zwecke).

Andererseits ist die uint_least8_t, usw. Typen sind überall dort nützlich, wo Sie die Verwendung von verschwenderisch großen oder langsamen Typen vermeiden möchten, aber sicherstellen müssen, dass Sie Werte einer bestimmten Größe speichern können. Zum Beispiel während long long mindestens 64 Bit ist, kann es auf einigen Maschinen 128 Bit sein, und die Verwendung, wenn Sie nur einen Typ benötigen, der 64-Bit-Zahlen speichern kann, wäre auf solchen Maschinen sehr verschwenderisch. int_least64_t löst das Problem.

Ich würde die Verwendung vermeiden [u]int_fastX_t Typen ganz da haben sie manchmal geändert auf einer bestimmten Maschine (Brechen des ABI) und da die Definitionen normalerweise falsch sind. Zum Beispiel wird auf x86_64 der 64-Bit-Integer-Typ als der „schnelle“ für 16-, 32- und 64-Bit-Werte angesehen, aber während Addition, Subtraktion und Multiplikation genau die gleiche Geschwindigkeit haben, unabhängig davon, ob Sie 32- Bit- oder 64-Bit-Werte, ist die Division bei Typen, die größer als nötig sind, mit ziemlicher Sicherheit langsamer, und selbst wenn sie die gleiche Geschwindigkeit hätten, verwenden Sie doppelt so viel Speicher ohne Nutzen.

Beachten Sie schließlich die Argumente, die einige Antworten über die Ineffizienz der Verwendung vorgebracht haben int32_t für einen Zähler, wenn es sich nicht um die native Integer-Größe handelt, sind technisch meistens korrekt, aber für den korrekten Code ist es irrelevant. Wenn Sie nicht eine kleine Anzahl von Dingen zählen, bei denen die maximale Anzahl unter Ihrer Kontrolle steht, oder eine externe (nicht im Speicher Ihres Programms) Sache, bei der die Anzahl astronomisch sein könnte, ist der richtige Typ für eine Zählung fast immer size_t. Aus diesem Grund werden alle Standard-C-Funktionen verwendet size_t für Zählungen. Erwägen Sie nicht, etwas anderes zu verwenden, es sei denn, Sie haben einen sehr guten Grund.

  • Das Problem mit int_fastx_t klingt eher nach einem Compiler-Fehler als nach etwas, mit dem sich der Programmierer befassen sollte. Und ich stimme zu, dass Zählervariablen (für Loop-Int-Interatoren usw.) in den meisten Fällen size_t sein sollten.

    – Ludin

    23. März 2012 um 12:31 Uhr

  • “Lesen/Schreiben von Festplatte/Netzwerk” ist die PC-Antwort. Sie benötigen auch definitiv stdint-Typen in jeder Form von eingebetteten Systemen, wo Sie mit Hardwareregistern, direktem Speicherzugriff, Speicherbehandlungsroutinen, Datenprotokollzuordnungen, Interrupt-Vektor-Setup, Bootloadern usw. zu tun haben.

    – Ludin

    23. März 2012 um 12:35 Uhr

  • @Lundin: Die Tatsache, dass es sich um einen weit verbreiteten “Fehler” handelt, zusammen mit dem Fehlen einer Spezifikation für die Definitionen dieser Typen im psABI, ist a sehr gut Grund zur Besorgnis des Programmierers. Wenn der Fehler jemals behoben wird, bedeutet dies, dass alle externen Schnittstellen, die diese Typen verwenden, die ABI-Kompatibilität beeinträchtigen. Schlimmer noch, die “Version” Ihrer Schnittstellen wird nicht von Ihrer Bibliotheksversion, sondern von Ihrer Compilerversion bestimmt.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    24. März 2012 um 0:10 Uhr

wallyks Benutzeravatar
Wallyk

Nachteile

Der Hauptgrund dafür, dass die Sprache C die Größe von nicht angibt int oder longusw. dienen der Recheneffizienz. Jede Architektur hat eine natürliche, effizienteste Größe, und die Designer haben den Compiler-Implementierer speziell ermächtigt und vorgesehen, die natürlichen nativen Datengrößendaten für Geschwindigkeit und Codegrößeneffizienz zu verwenden.

In den vergangenen Jahren war die Kommunikation mit anderen Maschinen kein Hauptanliegen – die meisten Programme waren lokal auf der Maschine –, sodass die Vorhersagbarkeit der Größe jedes Datentyps von geringer Bedeutung war.

Bestehen darauf, dass eine bestimmte Architektur eine bestimmte Größe verwendet int damit zu rechnen ist wirklich schlechte Ideeobwohl es andere Dinge einfacher zu machen scheint.

Dank XML und seinen Brüdern ist die Größe der Datentypen in gewisser Weise auch kein großes Problem mehr. Das Versenden von maschinenspezifischen Binärstrukturen von Maschine zu Maschine ist wiederum eher die Ausnahme als die Regel.

  • @Lundin: Typen wie int16_fast_t wäre viel nützlicher, wenn der Standard es Compilern erlauben würde, solchen Typen in Fällen, in denen dies effizienter wäre, zusätzliche Genauigkeit zu geben, ohne sie immer angeben zu müssen. Code, der an Speichereffizienz interessiert ist (bei eingebetteten Systemen üblich), könnte stark davon profitieren, wenn der Bereich einer Variablen davon abhängen könnte, ob sie in einem Register gespeichert wurde, selbst wenn es eine Regel gäbe, die besagt, dass der Bereich einer bestimmten Variablen erforderlich ist überall einheitlich. Unter einer solchen Regel int16_fast_t könnte auf vielen Maschinen so kompakt sein wie ein int16_t während…

    – Superkatze

    14. Mai 2015 um 19:00 Uhr


  • … immer noch alle Geschwindigkeitsvorteile, die realisiert werden könnten, wenn es befördert worden wäre int.

    – Superkatze

    14. Mai 2015 um 19:04 Uhr

Benutzeravatar von hroptatyr
Hroptatyr

Ich verwende stdint-Typen nur aus einem Grund, wenn die Daten, die ich im Speicher halte, in binärer Form auf Festplatte/Netzwerk/Deskriptor gehen sollen. Sie müssen nur das Little-Endian/Big-Endian-Problem bekämpfen, aber das ist relativ leicht zu überwinden.

Der offensichtliche Grund nicht stdint zu verwenden ist, wenn der Code größenunabhängig ist, in mathematischer Hinsicht alles, was über die rationalen ganzen Zahlen funktioniert. Es würde hässliche Code-Duplikate erzeugen, wenn Sie a angeben uint*_t Version von, sagen wir, qsort() für jede Erweiterung von *.

Ich verwende in diesem Fall meine eigenen Typen, abgeleitet von size_t wenn ich faul bin oder die größte unterstützte vorzeichenlose Ganzzahl auf der Plattform, wenn ich es nicht bin.

Bearbeiten, weil ich früher auf dieses Problem gestoßen bin:
Das finde ich zumindest bemerkenswert uint8_t, uint32_t und uint64_t sind in Solaris 2.5.1 defekt. Für maximale Portabilität empfehle ich daher immer noch, dies zu vermeiden stdint.h (zumindest für die nächsten Jahre).

1411580cookie-checkGründe für die Verwendung (oder Nichtverwendung) von stdint

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy