Min- und Max-Wert des Datentyps in C.

76

Was ist die Funktion, um den minimal und maximal möglichen Wert von Datentypen (dh int, char.etc) in C zu bestimmen?

SuperString
quelle

Antworten:

92

Sie möchten limits.hdie 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*_MINaus offensichtlichen Gründen weggelassen wird (jeder vorzeichenlose Typ hat einen Mindestwert von 0).

In ähnlicher Weise float.hbietet Grenzen für floatund doubleTypen:

-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.hsorgfältig lesen floatund doubledie 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.hbietet eine Reihe weiterer Konstanten , die Sie helfen, zu bestimmen , ob eine floatoder eine doubleDose, in der Tat, eine bestimmte Zahl darstellen.

Mark Elliot
quelle
2
Was ist der Min- und Max-Wert eines Floats?
SuperString
3
SIZE_MAX(maximale Größe von a size_t) ist eine weitere nützliche.
Café
size_t maxSize = SIZE_MAX;
Joey van Hummel
2
-FLT_MAX und FLT_MAX
JohnMudd
@ MartinBeckett nicht nach der Header-Datei, oder meine Erinnerungen daran, dies in C zu schreiben? FLT_MIN ist ungefähr Null, nein?
Adam
32

"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 maxofMakro 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.

Glyphe
quelle
Würde nicht ~((t) 0)für max von unsignierten arbeiten? (tut es nicht, aber ich bin mir noch nicht sicher warum).
Gauthier
Vielen Dank für die Informationen zur Signaturerkennung. Ich werde die Antwort aktualisieren.
Glyphe
1
Alle diese 8ULL-Konstanten sollten stattdessen wahrscheinlich CHAR_BIT sein.
jschultz410
umaxof (t) kann viel einfacher als ((t) -1) oder (~ (t) 0) geschrieben werden, die beide garantiert nach dem C-Standard funktionieren. smaxof (t) kann geschrieben werden ((t) ~ (1ULL << (sizeof (t) * CHARBIT - 1))). Signierte Mindestanforderungen sind viel schwieriger.
jschultz410
Große Daumen hoch auf maxof bedingt mit dem richtigen Makro abhängig von der Ausgabe!
jschultz410
7

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 Typ tgleich oder größer als ist unsigned int. (Diese Besetzung erzwingt eine Typförderung.)

  • ((t)~0U)// Wenn Sie wissen, dass Ihr Typ tkleiner als ist unsigned int. (Diese Besetzung stuft den Typ herab, nachdem der unsigned intAusdruck -type ~0Uausgewertet 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 das SIZE_MAXMakro) kann definiert werden als (~(size_t)0). Der Linux-Kernel-Quellcode definiert das SIZE_MAXMakro auf diese Weise.

Eine Einschränkung : Alle diese Ausdrücke verwenden entweder Typumwandlung oder sizeofOperator, sodass keiner dieser Ausdrücke unter Präprozessorbedingungen ( #if... #elif... #endifund ähnlichem) funktioniert .

(Die Antwort wurde aktualisiert, um Vorschläge von @chux und @ vinc17 aufzunehmen. Vielen Dank an beide.)

Explorer09
quelle
Beachten Sie, dass dies unsigned long longmöglicherweise nicht der größte Ganzzahltyp ist. uintmax_tsollte 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äprozessorbedingungen sizeofkönnen ebenfalls nicht verwendet werden, da die Vorverarbeitung vor der semantischen Analyse erfolgt, dh der Präprozessor hat keine Vorstellung von Typen.
vinc17
Die Methode "Maximalwert eines vorzeichenbehafteten Integraltyps" beruht hier auf Annahmen, wenn auch sehr häufigen. Beachten Sie, dass dies zwar ungewöhnlich xxx_MAX == Uxxx_MAXist, aber sowohl in C als auch in C zulässig ist xxx_MAX < Uxxx_MAX/2. Es wird angegeben, dass xxx_MAX <= Uxxx_MAXbeide Typen dieselbe Größe haben.
chux
@chux Was ich bisher gewusst habe, charist der einzige C-Standard-Typ, der möglicherweise erfüllt werden kann xxx_MAX == Uxxx_MAX, da er charje nach Implementierung signiert oder nicht signiert sein kann. Und für den xxx_MAX < Uxxx_MAX/2Fall ist es am wahrscheinlichsten, dass es durch eine Nicht-2-Komplement-Arithmetik verursacht wird (andernfalls macht es für eine Implementierung keinen Sinn).
Explorer09
1
~((t) 0)funktioniert nicht, wenn (t)0es schmaler als ein ist int.
chux
1
@chux Danke für den Hinweis zu ~((t) 0). Was die xxx_MAX == Uxxx_MAXund xxx_MAX < Uxxx_MAX/2Fälle betrifft, so sind sie nach dem , was ich im C99-Standard gelesen habe, zulässig.
Explorer09
4
#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;
}
rahul gupta
quelle
Wir können einfach den höchsten Wert des vorzeichenlosen Datentyps erhalten und ihn vom Maximalwert subtrahieren, um den Minimalwert zu erhalten.
Akansh
1
Dies ist eine großartige, systemunabhängige Antwort, die ein Verständnis der Typen, des Speichers und natürlich der bitweisen C-Operatoren demonstriert.
Jonathan Komar
@JonathanKomar Alle oben signierten Minima setzen eine 2er-Komplement-Architektur voraus, was normalerweise - aber nicht immer - in C der Fall ist.
jschultz410
Korrektur: systemabhängig (setzt eine 2er-Komplementinterpretation von Bits voraus) Danke jschultz410.
Jonathan Komar
3

Schauen Sie sich diese Seiten auf limit.h und float.h an , die Teil der Standard-c-Bibliothek sind.

Nixuz
quelle
3

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;
}
craig65535
quelle
3

Die Header-Datei limits.hdefiniert Makros, die auf verschiedene Grenzen und Parameter der Standard-Integer-Typen erweitert werden.

Prasoon Saurav
quelle
Was ist der Mindestwert für vorzeichenloses Zeichen?
SuperString
4
@ Superstring, der Mindestwert eines vorzeichenlosen Typs ist 0.
Mark Elliot
4
Ich möchte negative vorzeichenlose Werte! :-)
Alok Singhal
2

So erhalten Sie den Maximalwert eines vorzeichenlosen Integer-Typs, tdessen Breite mindestens der von ist unsigned 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 tsigniert 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 (selbst uintmax_tbei 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 < 0funktioniert 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
vinc17
quelle
Warum nicht einfacher für signiertes Maximum (~ ((t) 1 << (Größe von (t) * CHAR_BIT - 1)))?
jschultz410
1
@ jschultz410 Weil dies undefiniertes Verhalten ist. Der mathematische (und positive) Wert 2 zu sizeof(t) * CHAR_BIT - 1ist im vorzeichenbehafteten Typ nicht darstellbar t. 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.
vinc17
0

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));
Arjun
quelle