So überprüfen Sie, ob Ganzzahlen mit fester Breite definiert sind

25

In C ++ werden Ganzzahlen mit fester Breite als optional definiert , aber ich kann anscheinend nicht die empfohlene Methode finden, um zu überprüfen, ob sie tatsächlich definiert sind.

Was wäre eine tragbare Methode, um zu überprüfen, ob Ganzzahlen mit fester Breite verfügbar sind?

Rick de Water
quelle
Es scheint kein Feature-Test-Makro zu geben , aber ich nehme an, Sie können es tun#if defined(INT8_MIN)
Zereges
2
Wenn die Standardbibliothek dafür kein Feature-Test-Makro bereitstellt, können Sie prüfen, ob die von Ihnen verwendete Toolchain eines dafür bereitstellt oder ob Sie einen eigenen Test definieren können. Mit CMake können Sie beispielsweise bestimmte Sprachfunktionen testen, indem Sie eine definierte cppDatei kompilieren. Je nachdem, ob die Kompilierung fehlschlägt oder nicht, wird ein Makro festgelegt, das Sie definieren können.
t.niese
Wenn Sie Autoconf gegenüber cmake bevorzugen, sind Tests für diese vordefiniert. AC_TYPE_INT8_Tusw.
Shawn
Wenn jemand eine Tag-Bewertung in stdint hat , sollte IMO cstdint als Synonym nominiert werden ( stackoverflow.com/tags/stdint/synonyms ). Ich glaube nicht, dass wir für diese obskure Sache separate C- und C ++ - Tags benötigen. Das Haupt-Tag auf der Frage ist genug.
Peter Cordes
1
@PeterCordes Diesmal hat es funktioniert: stackoverflow.com/tags/stdint/synonyms
Andrew Henle

Antworten:

16

Um festzustellen, ob ein Integer-Typ mit fester Breite bereitgestellt wird, können Sie überprüfen, ob eines der entsprechenden [U]INT*_MAXoder [U]INT*_MINMakros definiert ist.

// may be necessary for your C++ implementation
#define __STDC_LIMIT_MACROS 
#include <cstdint>

#ifdef INT32_MAX
// int32_t must be available to get here
int32_t some32bitIntVariable;
#endif

Gemäß 7.20 Integer-Typen<stdint.h> , Absatz 4 des C11-Standards (beachten Sie die fettgedruckten Teile):

Für jeden hier beschriebenen Typ, den die Implementierung bereitstellt, <stdint.h>muss dieser typedefName deklariert und die zugehörigen Makros definiert werden . Umgekehrt <stdint.h>darf für jeden hier beschriebenen Typ, den die Implementierung nicht bereitstellt, dieser typedefName nicht deklariert oder die zugehörigen Makros definiert werden .

C ++ erbt die C-Implementierung über <cstdint>. Siehe <cstdint>vs<stdint.h> für einige Details. Siehe auch Was tun __STDC_LIMIT_MACROSund __STDC_CONSTANT_MACROSbedeuten? für Details zu __STDC_LIMIT_MACROS.

Also, wenn int32_tverfügbar, INT32_MAXund INT32_MINmuss #define'd sein. Umgekehrt, wenn int32_tnicht verfügbar, dürfen INT32_MAXund INT32_MINdürfen #define'd.

Beachten Sie jedoch, wie @NicolBolas in einer anderen Antwort angegeben hat , dass eine Überprüfung möglicherweise nicht erforderlich ist.

Andrew Henle
quelle
Es wird kürzer sein, nach [U]INT*_Cden
Min-
1
@phuclv Außer das ist nicht das gleiche. zB INT64_Cwird definiert, ob int64_least_tverfügbar ist, nicht wenn int64_tverfügbar ist. Siehe Dokumentation
Leichtigkeitsrennen im Orbit
19

Im Großen und Ganzen ... das tust du nicht.

Wenn Sie ganzzahlige Typen mit fester Größe verwenden müssen, bedeutet dies, dass diese Typen explizit ihre spezifische Größe haben müssen. Das heißt, Ihr Code ist nicht funktionsfähig, wenn Sie keine Ganzzahlen dieser Größen erhalten können. Sie sollten sie also einfach verwenden. Wenn jemand Ihren Code auf einem Compiler verwendet, dem diese Typen fehlen, wird Ihr Code nicht kompiliert. Was in Ordnung ist, weil Ihr Code nicht funktioniert hätte, wenn er kompiliert worden wäre.

Wenn Sie keine Ganzzahlen mit fester Größe benötigen, sondern diese nur aus einem anderen Grund möchten, verwenden Sie die int_least_*Typen. Wenn die Implementierung Ihnen genau diese Größe geben kann, haben die least_*Typen diese Größe.

Nicol Bolas
quelle
4
Das ist nicht wahr. Ich habe Stub-Passthroughs geschrieben, die operator = / etc für Plattformen implementieren, die uint8_t zuvor nicht unterstützen. Aus Effizienz- und Debugging-Gründen möchten Sie das Passthrough jedoch nur verwenden, wenn es tatsächlich erforderlich ist.
TLW
@TLW: " Ich habe Stub-Passthroughs geschrieben, die operator = / etc für Plattformen implementieren, die uint8_t vorher nicht unterstützen. " OK, aber ... warum? Welchen Code haben Sie geschrieben, der sicher sein muss, dass ein Byte 8 Bit hat (was vermutlich der Grund ist, warum Sie ihn verwendet haben uint8_t), aber dieser Code musste irgendwie auf einer Plattform ausgeführt werden, auf der ein Byte nicht 8 Bit enthält (was neben der Verwendung von a alte C ++ - Implementierung, wäre der einzige Grund, warum uint8_tnicht verfügbar wäre)? Das heißt, warum mussten Sie dies außerhalb der Abwärtskompatibilität tun?
Nicol Bolas
proprietär kann also nicht zu viel sagen. Gemeinsame Codebasis, die unter anderem einen ziemlich eigenartigen Hardware-Stack unterstützen musste. uint8_twar viel klarer als der vorherige Ad-hoc-Ansatz (und oft gebrochen).
TLW
Wenn Sie einen Algorithmus haben, der beispielsweise in 8-Bit-Bytes ausgedrückt wird, können Sie einen Passthrough einmal schreiben und sind einfach zu testen. Während das Reparieren jedes Ortes ad-hoc und leicht subtil falsch ist. O(1)versus O(n)Anstrengung. Gleicher Grund, warum Menschen zB verwenden uint16_t. Sie fragen "Warum nicht uint32_t verwenden und es selbst umsetzen?", Worauf die Antwort offensichtlich sein sollte.
TLW
@TLW: "Der gleiche Grund, warum Leute zB uint16_t verwenden. " Das ist nicht mein Grund für die Verwendung uint16_t. Mein Grund ist, dass ich mit einem Gerät / Format / etc kommuniziere, das erwartet, dass genau 16 Bit Daten als binäre, vorzeichenlose Ganzzahl unter Verwendung des Endians für meinen Computer formatiert werden, und wenn ich keinen Typ bekomme, der ist Genau das, dann ist es viel schwieriger, effektiv damit zu kommunizieren. Mein Programm (und die APIs, die ich damit verwende) können grundsätzlich nicht auf einem Computer funktionieren , der dies nicht bietet.
Nicol Bolas