簡體   English   中英

C中數據類型的最小值和最大值

[英]min and max value of data type in C

確定 C 中數據類型(即 int、char.etc)的最小值和最大值的函數是什么?

您需要使用limits.h ,它提供以下常量(根據鏈接的參考):

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
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
PTRDIFF_MIN    : minimum value of ptrdiff_t
PTRDIFF_MAX    : maximum value of ptrdiff_t
SIZE_MAX       : maximum value of size_t
SIG_ATOMIC_MIN : minimum value of sig_atomic_t
SIG_ATOMIC_MAX : maximum value of sig_atomic_t
WINT_MIN       : minimum value of wint_t
WINT_MAX       : maximum value of wint_t
WCHAR_MIN      : minimum value of wchar_t
WCHAR_MAX      : maximum value of wchar_t
CHAR_BIT       : number of bits in a char
MB_LEN_MAX     : maximum length of a multibyte character in bytes

其中U*_MIN由於顯而易見的原因被省略(任何無符號類型的最小值為 0)。

類似的float.hfloatdouble類型提供了限制:

FLT_MIN    : smallest normalised positive value of a float
FLT_MAX    : largest positive finite value of a float
DBL_MIN    : smallest normalised positive value of a double
DBL_MAX    : largest positive finite value of a double
LDBL_MIN   : smallest normalised positive value of a long double
LDBL_MAX   : largest positive finite value of a long double
FLT_DIG    : the number of decimal digits guaranteed to be preserved converting from text to float and back to text
DBL_DIG    : the number of decimal digits guaranteed to be preserved converting from text to double and back to text
LDBL_DIG   : the number of decimal digits guaranteed to be preserved converting from text to long double and back to text

浮點類型圍繞零對稱,因此最負的有限數是最正的有限數的否定 - 例如float范圍從-FLT_MAXFLT_MAX

請注意,浮點類型只能准確表示其范圍內的少量有限數量的值。 隨着存儲的絕對值變大,可以精確表示的相鄰數字之間的間距也變大。

“但是字形”,我聽到你問,“如果我必須確定一個不透明類型的最大值,它的最大值最終可能會改變呢?” 您可能會繼續:“如果它是我無法控制的庫中的 typedef 怎么辦?”

我很高興你問,因為我只是花了幾個小時來制定一個解決方案(然后我不得不扔掉它,因為它沒有解決我的實際問題)。

您可以使用這個方便的maxof宏來確定任何有效整數類型的大小。

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

你可以像這樣使用它:

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

如果您願意,您可以在這些宏的前面添加一個 '(t)',這樣它們就會為您提供您所詢問的類型的結果,並且您不必進行強制轉換以避免警告。

任何無符號整數類型的最大值

  • ((t)~(t)0) // 幾乎適用於所有情況的通用表達式。

  • (~(t)0) // 如果你知道你的類型t大小等於或大於unsigned int (此施法力型晉升。)

  • ((t)~0U) // 如果你知道你的類型t大小小於unsigned int (在評估unsigned int類型表達式~0U之后,此~0U將類型~0U 。)

任何有符號整數類型的最大值

  • 如果您有t類型的無符號變體, ((t)(((unsigned t)~(unsigned t)0)>>1))將為您提供所需的最快結果。

  • 否則,使用這個(感謝@vinc17 的建議): (((1ULL<<(sizeof(t)*CHAR_BIT-2))-1)*2+1)

任何有符號整數類型的最小值

您必須知道機器的簽名數字表示。 大多數機器使用 2 的補碼,因此-(((1ULL<<(sizeof(t)*CHAR_BIT-2))-1)*2+1)-1對你有用。

要檢測您的機器是否使用 2 的補碼,請檢測(~(t)0U)(t)(-1)表示相同的事物。

所以,結合上面:

(-(((1ULL<<(sizeof(t)*CHAR_BIT-2))-1)*2+1)-(((~(t)0U)==(t)(-1)))

將為您提供任何有符號整數類型的最小值。

例如: size_t最大值(又名SIZE_MAX宏)可以定義為(~(size_t)0) Linux 內核源代碼以這種方式定義SIZE_MAX宏。

需要注意的是:所有這些表達式都使用類型轉換或sizeof運算符,因此這些表達式都不適用於預處理器條件( #if ... #elif ... #endif等)。

(已更新答案以納入來自 @chux 和 @vinc17 的建議。謝謝你們。)

頭文件limits.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)

示例代碼:

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

查看limits.hfloat.h上的這些頁面,它們是標准c 庫的一部分。

要獲得寬度至少為unsigned int之一的unsigned int符號整數類型tunsigned int (否則整數提升會出現問題): ~(t) 0 如果還想支持更短的類型,可以添加另一個類型轉換: (t) ~(t) 0

如果整數類型t是有符號的,假設沒有填充位,可以使用:

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

這個公式的優點是它不是基於t一些無符號版本(或更大的類型),這可能是未知的或不可用的(即使uintmax_t可能不足以使用非標准擴展)。 6 位示例(實際上不可能,只是為了便於閱讀):

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

在二進制補碼中,最小值與最大值相反,即負 1(在 ISO C 標准允許的其他整數表示中,這正好與最大值相反)。

注意:要檢測符號以決定使用哪個版本: (t) -1 < 0將適用於任何整數表示,為有符號整數類型提供 1 (true),為無符號整數類型提供 0 (false)。 因此可以使用:

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

可以在不使用任何庫函數的情況下計算任何整數數據類型的 MIN 和 MAX 值,並且相同的邏輯可以應用於其他整數類型 short、int 和 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));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM