获取C中变量的最大值

在C中是否有一个函数返回这样的变量的最大值(我将在下面的例子中命名函数“maxvalue”)?

int a; printf("%d", maxvalue(a)); // 32767 unsigned int b; printf("%d", maxvalue(b)); // 65535 

所以基本上,当变量被赋值为INT时,函数返回值为INT_MAX ,当无符号为int时返回INT_MAX等。

C标准库没有定义这样的function。 您可以尝试定义计算它的宏:

 #define MAX_VALUE(a) (((unsigned long long)1 << (sizeof(a) * CHAR_BIT)) - 1) 

使用时,请注意将其分配给足够大的类型。 例如:

 #include  #include  #include  #define IS_TYPE_SIGNED(a) ((a-1) < 0) #define MAX_VALUE_UNSIGNED(a) (((unsigned long long)1 << \ (sizeof(a) * CHAR_BIT)) - 1) #define MAX_VALUE_SIGNED(a) (MAX_VALUE_UNSIGNED(a) >> 1) #define MAX_VALUE(a) (IS_TYPE_SIGNED(a) ? \ MAX_VALUE_SIGNED(a) : MAX_VALUE_UNSIGNED(a)) int main(void) { unsigned int i = 0; signed int j = 0; printf("%llu\n", MAX_VALUE(i)); printf("%llu\n", MAX_VALUE(j)); return EXIT_SUCCESS; } 

打印出:

 4294967295 2147483647 

您可以使用C11类型通用表达式轻松完成:

 #define maxvalue(type) _Generic(type, int: INT_MAX, \ unsigned int: UINT_MAX) 

它不是一个function,但我认为它可以满足您的需求。 这是一个简单的示例程序:

 #include  #include  #define maxvalue(type) _Generic(type, int: INT_MAX, \ unsigned int: UINT_MAX) int main(void) { int i; unsigned int ui; printf("%u\n", maxvalue(i)); printf("%u\n", maxvalue(ui)); return 0; } 

它的输出:

 $ clang -Wall -Werror -Wextra -pedantic -std=c11 example.c -o example $ ./example 2147483647 4294967295 

我的答案比你的大,因为我的系统有32位整数。 您似乎有一台16位计算机。

以下是我的库中用于类型而不是变量的宏:

 /* min and max integer values. T is a signed or unsigned integer type. */ /* Returns 1 if T is signed, else 0. */ #define INTTYPE_SIGNED(T) ((T)-1 < (T)0) /* * Returns (T)(maximum value of a T). * * Pains are taken (perhaps unnecessarily) to avoid integer overflow * with signed types. */ #define INTTYPE_MAX(T) \ (((T)1 << (CHAR_BIT*sizeof(T)-INTTYPE_SIGNED(T)-1)) - 1 + \ ((T)1 << (CHAR_BIT*sizeof(T)-INTTYPE_SIGNED(T)-1))) /* * Returns (T)(minimum value of a T). * Pains are taken (perhaps unnecessarily) to avoid integer overflow * with signed types. * assert: twos complement architecture */ #define INTTYPE_MIN(T) ((T)(-INTTYPE_MAX(T)-1)) 

编辑:根据问题调整这些:

 /* min and max integer values. V is a signed or unsigned integer value. */ /* Returns 1 if V has signed type, else 0. */ #define INT_VALUE_SIGNED(V) ((V)-(V)-1 < 0) /* * Returns maximum value for V's type. * * Pains are taken (perhaps unnecessarily) to avoid integer overflow * with signed types. */ #define INT_VALUE_MAX(V) \ (((V)-(V)+1 << (CHAR_BIT*sizeof(V)-INT_VALUE_SIGNED(V)-1)) - 1 + \ ((V)-(V)+1 << (CHAR_BIT*sizeof(V)-INT_VALUE_SIGNED(V)-1))) /* * Returns minimum value for V's type. * Pains are taken (perhaps unnecessarily) to avoid integer overflow * with signed types. * assert: twos complement architecture */ #define INT_VALUE_MIN(V) (-INT_VALUE_MAX(V)-1) 

事后考虑:如果V是一个变量,或者一个包含变量的表达式,它们会调用UB,而这些变量没有被赋值......这就是问题中的情况。 它们很可能适用于许多实现,但C标准并不能保证它,并且它们肯定会在使用陷阱值初始化未初始化变量的实现上失败。

不,标准C实现中不存在这样的function。

您无法创建执行此操作的函数,但您可以创建一些执行此操作的宏。

如果你有C11,你可以使用_Generic :

 #define maxvalue(x) \ _Generic(x, \ char: 127, short: 32767, int: INT_MAX, \ unsigned char: 255, unsigned short: 65535, unsigned int: UINT_MAX) 

如果你需要C89,你可以做到这一点,如果你可以区分签名/未签名:

 #define maxvalue_unsigned(x) ((1<<(8*sizeof(x)))-1) #define maxvalue_signed(x) ((1<<((8*sizeof(x)-1)))-1) 

如果您愿意要求typename(或使用GCC特定的typename ),您可以使用字符串:

 #define maxvalue_type(x) maxvalue_helper(#x "----------") unsigned long long maxvalue_helper(const char *s) { switch(*s){ char 'c': /* char */ return 127; char 's': /* short */ return 32767; char 'i': /* int */ return INT_MAX; /* ... */ case 'u': /* unsigned */ switch(9[s]) { case 'c': /* unsigned char */ return 255; char 's': /* unsigned short */ return 65535; char 'i': /* unsigned int */ return UINT_MAX; /* ... */ 

看起来我已经能够提出一个相对易于使用的宏SIGNED_VAR(VAR)来测试给定的整数变量是否通过修改,比较和恢复变量的值来签名(所有这些只是类型所必需的)小于int )同时避免未定义的行为,特别是与有符号溢出和序列点相关的种类。 或者看起来如此。 至少,gcc(用-Wall调用)不会抱怨我在&&||之间做了一些疯狂的事情 运营商,虽然它不喜欢三元组周围的同类事物?:运营商。

关于这个宏的优点是它应该与C89和C99编译器一起使用( 1LL可以用1L替换, long long可以替换为long (当然) "%ll"替换为"%l" )如果你的C89编译器没有来自C99的扩展long long类型,并且它也正确地支持小于intcharshort )的类型。

一旦我们知道变量是否已签名,构造最小值和最大值是微不足道的,许多人已经说明了如何做到这一点。 宏VAR_MAX()VAR_MIN()构造这些值并将它们作为最长的C99整数类型返回。 我选择返回签名类型,以避免在将无符号值转换为有符号时出现潜在的溢出/ UB问题。 由于返回的long long类型不能直接将unsigned long longULLONG_MAX )的最大值表示为有符号值,如果需要返回该值,则返回-1,在转换为unsigned long long将生成ULLONG_MAX 。 你需要在这里小心一点。

这是丑陋的。 希望,我没有错过任何一个错误。

哦,当然,预计在签名类型中支持2的补码值的整个非对称范围(例如min = -128,max = + 127)。

编辑 :我忘了提到SIGNED_VAR()期望变量被初始化。 否则,读取它可能会导致未定义的行为。

 // file: IntVarMinMax.c // compile: gcc -Wall -std=c99 -O2 IntVarMinMax.c -o IntVarMinMax.exe #include  #include  #include  int SignTestTestVal; unsigned char SignTestOriginalXchar; unsigned short SignTestOriginalXshort; signed char SignTestRestoreOriginalXchar(void) { if (SignTestOriginalXchar < SCHAR_MAX + 1u) return (signed char)SignTestOriginalXchar; return (signed char)(SignTestOriginalXchar - SCHAR_MAX - 1) - SCHAR_MAX - 1; } short SignTestRestoreOriginalXshort(void) { if (SignTestOriginalXshort < SHRT_MAX + 1u) return (short)SignTestOriginalXshort; return (short)(SignTestOriginalXshort - SHRT_MAX - 1) - SHRT_MAX - 1; } #define IFELSE(E1,E2,E3) (((E1) && (E2)) || (!(E1) && (E3))) #define SEQ(E1,E2) (((E1) && (E2)) || (E2)) #define SIGNED_VAR(VAR) \ ( \ IFELSE \ ( \ sizeof(VAR) >= sizeof(int), \ ((VAR) - (VAR) - 1 < 0), \ IFELSE \ ( \ sizeof(VAR) == sizeof(short), \ SEQ(SignTestOriginalXshort = (VAR), \ SEQ(SignTestTestVal = (VAR) = -1, \ SEQ((VAR) = SignTestRestoreOriginalXshort(), \ SignTestTestVal < 0))), \ IFELSE \ ( \ sizeof(VAR) == sizeof(char), \ SEQ(SignTestOriginalXchar = (VAR), \ SEQ(SignTestTestVal = (VAR) = -1, \ SEQ((VAR) = SignTestRestoreOriginalXchar(), \ SignTestTestVal < 0))), \ (fprintf(stderr, "unsupported type!"), exit(-1), 0) \ ) \ ) \ ) \ ) #define VAR_MAX(SIGNED,VAR) \ ( \ SIGNED ? \ ((1ll << (sizeof(VAR) * CHAR_BIT - 2)) - 1 + \ (1ll << (sizeof(VAR) * CHAR_BIT - 2))) : \ ( \ (sizeof(VAR) < sizeof(long long)) ? \ ((1ll << (sizeof(VAR) * CHAR_BIT - 1)) - 1 + \ (1ll << (sizeof(VAR) * CHAR_BIT - 1))) : \ ( \ (sizeof(VAR) == sizeof(long long)) ? \ -1ll : \ (fprintf(stderr, "unsupported type!"), exit(-1), 0) \ ) \ ) \ ) #define VAR_MIN(SIGNED,VAR) \ ( \ SIGNED ? \ (-((1ll << (sizeof(VAR) * CHAR_BIT - 2)) - 1 + \ (1ll << (sizeof(VAR) * CHAR_BIT - 2))) - 1) : \ 0 \ ) int main(void) { signed char sc = 1; char c = 2; unsigned char uc = 3; short ss = 4; unsigned short us = 5; int si = 6; unsigned int ui = 7; long sl = 8; unsigned long ul = 9; long long sll = 10; unsigned long long ull = 11; #define PRINT_VARS() \ printf("sc=%hhd, c=%hhu, uc=%hhu, " \ "ss=%hd, us=%hu, si=%d, ui=%u, " \ "sl=%ld, ul=%lu, sll=%lld, ull=%llu\n", \ sc, c, uc, \ ss, us, si, ui, \ sl, ul, sll, ull) #define TEST_VAR(VAR) \ { \ int varIsSigned = SIGNED_VAR(VAR); \ if (varIsSigned) \ printf("%lld <= " #VAR " <= %lld\n", \ VAR_MIN(varIsSigned,VAR), \ VAR_MAX(varIsSigned,VAR)); \ else \ printf("%lld <= " #VAR " <= %llu\n", \ VAR_MIN(varIsSigned,VAR), \ (unsigned long long)VAR_MAX(varIsSigned,VAR)); \ } PRINT_VARS(); TEST_VAR(sc); TEST_VAR(c); TEST_VAR(uc); TEST_VAR(ss); TEST_VAR(us); TEST_VAR(si); TEST_VAR(ui); TEST_VAR(sl); TEST_VAR(ul); TEST_VAR(sll); TEST_VAR(ull); PRINT_VARS(); return 0; } 

输出( ideone ):

 sc=1, c=2, uc=3, ss=4, us=5, si=6, ui=7, sl=8, ul=9, sll=10, ull=11 -128 <= sc <= 127 -128 <= c <= 127 0 <= uc <= 255 -32768 <= ss <= 32767 0 <= us <= 65535 -2147483648 <= si <= 2147483647 0 <= ui <= 4294967295 -2147483648 <= sl <= 2147483647 0 <= ul <= 4294967295 -9223372036854775808 <= sll <= 9223372036854775807 0 <= ull <= 18446744073709551615 sc=1, c=2, uc=3, ss=4, us=5, si=6, ui=7, sl=8, ul=9, sll=10, ull=11 

可以使用ANSI C 89轻松完成:

  #include #include int main(void) { printf("Max value of char: %d\n", CHAR_MAX); printf("Min value of char: %d\n", CHAR_MIN); printf("Max value of short: %d\n", SHRT_MAX); printf("Min value of short: %d\n", SHRT_MIN); printf("Max value of int: %d\n", INT_MAX); printf("Min value of int: %d\n", INT_MIN); printf("\n\n"); return 0; } 

请注意,您可以包含float.h,然后使用:

 printf("Max value of Double: %d\n", DBL_MAX); 

虽然,它不太值得推荐。

祝你好运,罗恩