valore minimo e massimo del tipo di dati in C

Qual è la funzione per determinare il minimo e il massimo ansible del valore dei tipi di dati (ad esempio, int, char.etc) in C?

Dovrai usare limits.h che fornisce le seguenti costanti (come per il riferimento collegato):

 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 

Dove U*_MIN viene omesso per ovvi motivi (qualsiasi tipo senza segno ha un valore minimo di 0).

Allo stesso modo float.h fornisce i limiti per i tipi float e double :

 -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 

Dovresti leggere attentamente l’articolo su floats.h , anche se float e double possono contenere i valori minimo e massimo prescritti, ma la precisione con cui ciascun tipo può rappresentare i dati potrebbe non corrispondere a ciò che stai cercando di memorizzare. In particolare, è difficile memorizzare numeri eccezionalmente grandi con frazioni estremamente piccole collegate. Quindi float.h fornisce un numero di altre costanti che ti aiutano a determinare se un float o un double possono, di fatto, rappresentare un numero particolare.

“Ma glifo”, ti sento chiedere, “e se dovessi determinare il valore massimo per un tipo opaco il cui massimo potrebbe eventualmente cambiare?” Potresti continuare: “E se si tratta di un typedef in una libreria che non controllo?”

Sono contento che tu abbia chiesto, perché ho appena passato un paio d’ore a preparare una soluzione (che poi ho dovuto buttare via, perché non risolveva il mio problema reale).

È ansible utilizzare questa utile maxof macro per determinare la dimensione di qualsiasi tipo intero valido.

 #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))) 

Puoi usarlo in questo modo:

 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; } 

Se vuoi, puoi lanciare un '(t)' sulla parte anteriore di quei macro in modo che ti diano un risultato del tipo che stai chiedendo, e non devi fare casting per evitare gli avvertimenti.

Valore massimo di qualsiasi tipo di integrale non firmato : (~(t)0)

Valore massimo di qualsiasi tipo integrale firmato : se hai una variante unsigned di tipo t, ((t)((~(unsigned t)0)>>1)) otterrai il risultato più veloce di cui hai bisogno (vedi esempio nel kernel di Linux codice sorgente indicato di seguito). Altrimenti dovresti probabilmente usare (~(1ULL<<(sizeof(t)*CHAR_BIT-1))) .

Valore minimo di qualsiasi tipo integrale firmato : Devi conoscere la rappresentazione del numero firmato della tua macchina. La maggior parte delle macchine usa il complemento a 2, e così -(~(1ULL<<(sizeof(t)*CHAR_BIT-1)))-1 funzionerà per te.

Per rilevare se la tua macchina usa il complemento a 2, scopri se (~(t)0U) e (t)(-1) rappresentano la stessa cosa. Quindi, combinato con sopra:

 ((~(t)0U) == (t)(-1) ? -(~(1ULL<<(sizeof(t)*CHAR_BIT-1)))-1 : -(~(1ULL<<(sizeof(t)*CHAR_BIT-1)))) 

fornirà il valore minimo di qualsiasi tipo integrale firmato. (In realtà ci sono altre rappresentazioni di questo se si conosce la rappresentazione del complemento a 2. Ad esempio (t)(1ULL<<(sizeof(t)*CHAR_BIT-1)) dovrebbe essere equivalente a (t)(-(~(1ULL<<(sizeof(t)*CHAR_BIT-1)))-1) )

Ad esempio: (~ (size_t) 0) ti dà il valore massimo di size_t. (E indovina un po ', questo è come SIZE_MAX è # definito nel codice sorgente del kernel di Linux .)

Un avvertimento : tutte queste espressioni usano il cast di tipo e quindi non funzionano nei condizionali del preprocessore (#if ... #elif ... #endif e simili).

Guarda queste pagine su limits.h e float.h , che sono incluse come parte della libreria c standard.

Ho scritto alcune macro che restituiscono il minimo e il massimo di qualsiasi tipo, indipendentemente dalla firma:

 #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) 

Codice di esempio:

 #include  #include  #include  #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; } 

Il file di intestazione limits.h definisce le macro che si espandono a vari limiti e parametri dei tipi di interi standard.

 #include 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; } 

I valori MIN e MAX di qualsiasi tipo di dati intero possono essere calcolati senza utilizzare alcuna funzione di libreria come di seguito e la stessa logica può essere applicata ad altri tipi interi short, int e long.

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

Per ottenere il valore massimo di un intero senza segno di tipo t cui larghezza è almeno quella di unsigned int (altrimenti si hanno problemi con le promozioni di interi): ~(t) 0 . Se si vuole supportare anche i tipi più brevi, si può aggiungere un altro cast: (t) ~(t) 0 .

Se il numero intero t è firmato, supponendo che non ci siano bit di riempimento, si può usare:

 ((((t) 1 << (sizeof(t) * CHAR_BIT - 2)) - 1) * 2 + 1) 

Il vantaggio di questa formula è che non si basa su una versione non firmata di t (o di un tipo più grande), che può essere sconosciuta o non disponibile (anche uintmax_t potrebbe non essere sufficiente con estensioni non standard). Esempio con 6 bit (non ansible in pratica, solo per la leggibilità):

 010000 (t) 1 << (sizeof(t) * CHAR_BIT - 2) 001111 - 1 011110 * 2 011111 + 1 

Nel complemento a due, il valore minimo è l'opposto del valore massimo, meno 1 (nelle altre rappresentazioni di interi consentite dallo standard ISO C, questo è esattamente l'opposto del valore massimo).

Nota: per rilevare la firma per decidere quale versione utilizzare: (t) -1 < 0 funzionerà con qualsiasi rappresentazione intera, dando 1 (vero) per i tipi di interi con segno e 0 (falso) per i tipi di numeri interi senza segno. Quindi si può usare:

 (t) -1 < 0 ? ((((t) 1 << (sizeof(t) * CHAR_BIT - 2)) - 1) * 2 + 1) : (t) ~(t) 0