Was ist die Funktion, um den minimal und maximal möglichen Wert von Datentypen (dh int, char.etc) in C zu bestimmen?
Sie möchten limits.h
die folgenden Konstanten verwenden (gemäß der verknüpften Referenz):
CHAR_BIT = number of bits in a char
SCHAR_MIN = minimum value for a signed char
SCHAR_MAX = maximum value for a signed char
UCHAR_MAX = maximum value for an unsigned char
CHAR_MIN = minimum value for a char
CHAR_MAX = maximum value for a char
MB_LEN_MAX = maximum multibyte length of a character accross locales
SHRT_MIN = minimum value for a short
SHRT_MAX = maximum value for a short
USHRT_MAX = maximum value for an unsigned short
INT_MIN = minimum value for an int
INT_MAX = maximum value for an int
UINT_MAX = maximum value for an unsigned int
LONG_MIN = minimum value for a long
LONG_MAX = maximum value for a long
ULONG_MAX = maximum value for an unsigned long
LLONG_MIN = minimum value for a long long
LLONG_MAX = maximum value for a long long
ULLONG_MAX = maximum value for an unsigned long long
Wo U*_MIN
aus offensichtlichen Gründen weggelassen wird (jeder vorzeichenlose Typ hat einen Mindestwert von 0).
In ähnlicher Weise float.h
bietet Grenzen für float
und double
Typen:
-FLT_MAX = most negative value of a float
FLT_MAX = max value of a float
-DBL_MAX = most negative value of a double
DBL_MAX = max value of a double
-LDBL_MAX = most negative value of a long double
LDBL_MAX = max value of a long double
Sie sollten den Artikel jedoch floats.h
sorgfältig lesen float
und double
die vorgeschriebenen Minimal- und Maximalwerte einhalten, aber die Genauigkeit, mit der jeder Typ Daten darstellen kann, stimmt möglicherweise nicht mit dem überein, was Sie speichern möchten. Insbesondere ist es schwierig, außergewöhnlich große Zahlen mit extrem kleinen Fraktionen zu speichern. So float.h
bietet eine Reihe weiterer Konstanten , die Sie helfen, zu bestimmen , ob eine float
oder eine double
Dose, in der Tat, eine bestimmte Zahl darstellen.
SIZE_MAX
(maximale Größe von asize_t
) ist eine weitere nützliche."Aber Glyphe", höre ich Sie fragen, "was ist, wenn ich den Maximalwert für einen undurchsichtigen Typ bestimmen muss, dessen Maximum sich eventuell ändern könnte?" Sie könnten fortfahren: "Was ist, wenn es sich um ein typedef in einer Bibliothek handelt, die ich nicht kontrolliere?"
Ich bin froh, dass Sie gefragt haben, weil ich nur ein paar Stunden damit verbracht habe, eine Lösung zu finden (die ich dann wegwerfen musste, weil sie mein eigentliches Problem nicht gelöst hat).
Mit diesem praktischen
maxof
Makro können Sie die Größe eines gültigen Ganzzahltyps bestimmen.#define issigned(t) (((t)(-1)) < ((t) 0)) #define umaxof(t) (((0x1ULL << ((sizeof(t) * 8ULL) - 1ULL)) - 1ULL) | \ (0xFULL << ((sizeof(t) * 8ULL) - 4ULL))) #define smaxof(t) (((0x1ULL << ((sizeof(t) * 8ULL) - 1ULL)) - 1ULL) | \ (0x7ULL << ((sizeof(t) * 8ULL) - 4ULL))) #define maxof(t) ((unsigned long long) (issigned(t) ? smaxof(t) : umaxof(t)))
Sie können es so verwenden:
int main(int argc, char** argv) { printf("schar: %llx uchar: %llx\n", maxof(char), maxof(unsigned char)); printf("sshort: %llx ushort: %llx\n", maxof(short), maxof(unsigned short)); printf("sint: %llx uint: %llx\n", maxof(int), maxof(unsigned int)); printf("slong: %llx ulong: %llx\n", maxof(long), maxof(unsigned long)); printf("slong long: %llx ulong long: %llx\n", maxof(long long), maxof(unsigned long long)); return 0; }
Wenn Sie möchten, können Sie ein '(t)' auf die Vorderseite dieser Makros werfen, damit Sie ein Ergebnis des Typs erhalten, nach dem Sie fragen, und Sie müssen kein Casting durchführen, um Warnungen zu vermeiden.
quelle
~((t) 0)
für max von unsignierten arbeiten? (tut es nicht, aber ich bin mir noch nicht sicher warum).Maximalwert eines vorzeichenlosen Integraltyps:
((t)~(t)0)
// Generischer Ausdruck, der unter fast allen Umständen funktionieren würde.(~(t)0)
// Wenn Sie wissen, dass Ihr Typt
gleich oder größer als istunsigned int
. (Diese Besetzung erzwingt eine Typförderung.)((t)~0U)
// Wenn Sie wissen, dass Ihr Typt
kleiner als istunsigned int
. (Diese Besetzung stuft den Typ herab, nachdem derunsigned int
Ausdruck -type~0U
ausgewertet wurde.)Maximalwert eines vorzeichenbehafteten Integraltyps:
Wenn Sie eine nicht signierte Variante des Typs haben
t
, erhalten((t)(((unsigned t)~(unsigned t)0)>>1))
Sie das schnellste Ergebnis, das Sie benötigen.Andernfalls verwenden Sie dies (danke an @ vinc17 für den Vorschlag):
(((1ULL<<(sizeof(t)*CHAR_BIT-2))-1)*2+1)
Mindestwert aller signierten Integraltyps:
Sie müssen die vorzeichenbehaftete Nummerndarstellung Ihres Geräts kennen. Die meisten Maschinen verwenden das 2er-Komplement und so weiter
-(((1ULL<<(sizeof(t)*CHAR_BIT-2))-1)*2+1)-1
funktionieren daher für Sie.Um festzustellen, ob Ihre Maschine das Zweierkomplement verwendet, prüfen Sie, ob
(~(t)0U)
und(t)(-1)
stellen Sie dasselbe dar.Also, kombiniert mit oben:
(-(((1ULL<<(sizeof(t)*CHAR_BIT-2))-1)*2+1)-(((~(t)0U)==(t)(-1)))
gibt Ihnen den Mindestwert eines vorzeichenbehafteten Integraltyps.
Als Beispiel: Der Maximalwert von
size_t
(auch bekannt als dasSIZE_MAX
Makro) kann definiert werden als(~(size_t)0)
. Der Linux-Kernel-Quellcode definiert dasSIZE_MAX
Makro auf diese Weise.Eine Einschränkung : Alle diese Ausdrücke verwenden entweder Typumwandlung oder
sizeof
Operator, sodass keiner dieser Ausdrücke unter Präprozessorbedingungen (#if
...#elif
...#endif
und ähnlichem) funktioniert .(Die Antwort wurde aktualisiert, um Vorschläge von @chux und @ vinc17 aufzunehmen. Vielen Dank an beide.)
quelle
unsigned long long
möglicherweise nicht der größte Ganzzahltyp ist.uintmax_t
sollte besser sein, ist aber in der Praxis nicht immer der größte ganzzahlige Typ (siehe GCCs__int128
). Ich habe in meiner Antwort eine tragbarere Lösung für das Maximum der signierten Typen angegeben. Dann könnte das Minimum wie Sie daraus abgeleitet werden. Die Präprozessorbedingungensizeof
können ebenfalls nicht verwendet werden, da die Vorverarbeitung vor der semantischen Analyse erfolgt, dh der Präprozessor hat keine Vorstellung von Typen.xxx_MAX == Uxxx_MAX
ist, aber sowohl in C als auch in C zulässig istxxx_MAX < Uxxx_MAX/2
. Es wird angegeben, dassxxx_MAX <= Uxxx_MAX
beide Typen dieselbe Größe haben.char
ist der einzige C-Standard-Typ, der möglicherweise erfüllt werden kannxxx_MAX == Uxxx_MAX
, da erchar
je nach Implementierung signiert oder nicht signiert sein kann. Und für denxxx_MAX < Uxxx_MAX/2
Fall ist es am wahrscheinlichsten, dass es durch eine Nicht-2-Komplement-Arithmetik verursacht wird (andernfalls macht es für eine Implementierung keinen Sinn).~((t) 0)
funktioniert nicht, wenn(t)0
es schmaler als ein istint
.~((t) 0)
. Was diexxx_MAX == Uxxx_MAX
undxxx_MAX < Uxxx_MAX/2
Fälle betrifft, so sind sie nach dem , was ich im C99-Standard gelesen habe, zulässig.#include<stdio.h> int main(void) { printf("Minimum Signed Char %d\n",-(char)((unsigned char) ~0 >> 1) - 1); printf("Maximum Signed Char %d\n",(char) ((unsigned char) ~0 >> 1)); printf("Minimum Signed Short %d\n",-(short)((unsigned short)~0 >>1) -1); printf("Maximum Signed Short %d\n",(short)((unsigned short)~0 >> 1)); printf("Minimum Signed Int %d\n",-(int)((unsigned int)~0 >> 1) -1); printf("Maximum Signed Int %d\n",(int)((unsigned int)~0 >> 1)); printf("Minimum Signed Long %ld\n",-(long)((unsigned long)~0 >>1) -1); printf("Maximum signed Long %ld\n",(long)((unsigned long)~0 >> 1)); /* Unsigned Maximum Values */ printf("Maximum Unsigned Char %d\n",(unsigned char)~0); printf("Maximum Unsigned Short %d\n",(unsigned short)~0); printf("Maximum Unsigned Int %u\n",(unsigned int)~0); printf("Maximum Unsigned Long %lu\n",(unsigned long)~0); return 0; }
quelle
Schauen Sie sich diese Seiten auf limit.h und float.h an , die Teil der Standard-c-Bibliothek sind.
quelle
Ich habe einige Makros geschrieben, die unabhängig von der Signatur die Min- und Max-Werte eines beliebigen Typs zurückgeben:
#define MAX_OF(type) \ (((type)(~0LLU) > (type)((1LLU<<((sizeof(type)<<3)-1))-1LLU)) ? (long long unsigned int)(type)(~0LLU) : (long long unsigned int)(type)((1LLU<<((sizeof(type)<<3)-1))-1LLU)) #define MIN_OF(type) \ (((type)(1LLU<<((sizeof(type)<<3)-1)) < (type)1) ? (long long int)((~0LLU)-((1LLU<<((sizeof(type)<<3)-1))-1LLU)) : 0LL)
Beispielcode:
#include <stdio.h> #include <sys/types.h> #include <inttypes.h> #define MAX_OF(type) \ (((type)(~0LLU) > (type)((1LLU<<((sizeof(type)<<3)-1))-1LLU)) ? (long long unsigned int)(type)(~0LLU) : (long long unsigned int)(type)((1LLU<<((sizeof(type)<<3)-1))-1LLU)) #define MIN_OF(type) \ (((type)(1LLU<<((sizeof(type)<<3)-1)) < (type)1) ? (long long int)((~0LLU)-((1LLU<<((sizeof(type)<<3)-1))-1LLU)) : 0LL) int main(void) { printf("uint32_t = %lld..%llu\n", MIN_OF(uint32_t), MAX_OF(uint32_t)); printf("int32_t = %lld..%llu\n", MIN_OF(int32_t), MAX_OF(int32_t)); printf("uint64_t = %lld..%llu\n", MIN_OF(uint64_t), MAX_OF(uint64_t)); printf("int64_t = %lld..%llu\n", MIN_OF(int64_t), MAX_OF(int64_t)); printf("size_t = %lld..%llu\n", MIN_OF(size_t), MAX_OF(size_t)); printf("ssize_t = %lld..%llu\n", MIN_OF(ssize_t), MAX_OF(ssize_t)); printf("pid_t = %lld..%llu\n", MIN_OF(pid_t), MAX_OF(pid_t)); printf("time_t = %lld..%llu\n", MIN_OF(time_t), MAX_OF(time_t)); printf("intptr_t = %lld..%llu\n", MIN_OF(intptr_t), MAX_OF(intptr_t)); printf("unsigned char = %lld..%llu\n", MIN_OF(unsigned char), MAX_OF(unsigned char)); printf("char = %lld..%llu\n", MIN_OF(char), MAX_OF(char)); printf("uint8_t = %lld..%llu\n", MIN_OF(uint8_t), MAX_OF(uint8_t)); printf("int8_t = %lld..%llu\n", MIN_OF(int8_t), MAX_OF(int8_t)); printf("uint16_t = %lld..%llu\n", MIN_OF(uint16_t), MAX_OF(uint16_t)); printf("int16_t = %lld..%llu\n", MIN_OF(int16_t), MAX_OF(int16_t)); printf("int = %lld..%llu\n", MIN_OF(int), MAX_OF(int)); printf("long int = %lld..%llu\n", MIN_OF(long int), MAX_OF(long int)); printf("long long int = %lld..%llu\n", MIN_OF(long long int), MAX_OF(long long int)); printf("off_t = %lld..%llu\n", MIN_OF(off_t), MAX_OF(off_t)); return 0; }
quelle
Die Header-Datei
limits.h
definiert Makros, die auf verschiedene Grenzen und Parameter der Standard-Integer-Typen erweitert werden.quelle
So erhalten Sie den Maximalwert eines vorzeichenlosen Integer-Typs,
t
dessen Breite mindestens der von istunsigned int
(andernfalls treten Probleme mit Ganzzahl-Heraufstufungen auf) :~(t) 0
. Wenn man auch kürzere Typen unterstützen möchte, kann man eine weitere Besetzung hinzufügen:(t) ~(t) 0
.Wenn der Integer-Typ
t
signiert ist und angenommen wird, dass keine Auffüllbits vorhanden sind, kann Folgendes verwendet werden:((((t) 1 << (sizeof(t) * CHAR_BIT - 2)) - 1) * 2 + 1)
Der Vorteil dieser Formel besteht darin, dass sie nicht auf einer nicht signierten Version von
t
(oder einem größeren Typ) basiert , die möglicherweise unbekannt oder nicht verfügbar ist (selbstuintmax_t
bei nicht standardmäßigen Erweiterungen möglicherweise nicht ausreicht). Beispiel mit 6 Bits (in der Praxis nicht möglich, nur zur besseren Lesbarkeit):010000 (t) 1 << (sizeof(t) * CHAR_BIT - 2) 001111 - 1 011110 * 2 011111 + 1
Im Zweierkomplement ist der Minimalwert das Gegenteil des Maximalwerts minus 1 (in den anderen vom ISO C-Standard zugelassenen Ganzzahldarstellungen ist dies genau das Gegenteil des Maximalwerts).
Hinweis: So erkennen Sie die Vorzeichen, um zu entscheiden, welche Version verwendet werden soll:
(t) -1 < 0
funktioniert mit jeder Ganzzahldarstellung, wobei 1 (wahr) für vorzeichenbehaftete Ganzzahltypen und 0 (falsch) für vorzeichenlose Ganzzahltypen angegeben wird. Somit kann man verwenden:(t) -1 < 0 ? ((((t) 1 << (sizeof(t) * CHAR_BIT - 2)) - 1) * 2 + 1) : (t) ~(t) 0
quelle
sizeof(t) * CHAR_BIT - 1
ist im vorzeichenbehafteten Typ nicht darstellbart
. Sie gehen von einem "Wrapping" -Verhalten der Linksverschiebung aus, das nicht Standard ist (und bei der Optimierung von Compilern möglicherweise fehlschlägt) und in den ganzzahligen Darstellungen, die sich vom Zweierkomplement unterscheiden (wie es der C-Standard zulässt), nicht einmal Sinn macht.MIN- und MAX-Werte eines beliebigen Integer-Datentyps können ohne Verwendung der folgenden Bibliotheksfunktionen berechnet werden, und dieselbe Logik kann auf andere Integer-Typen short, int und long angewendet werden.
printf("Signed Char : MIN -> %d & Max -> %d\n", ~(char)((unsigned char)~0>>1), (char)((unsigned char)~0 >> 1)); printf("Unsigned Char : MIN -> %u & Max -> %u\n", (unsigned char)0, (unsigned char)(~0));
quelle