C中是否有一个函数返回这样的变量的最大值(我将在下面的示例中将函数命名为“maxvalue”)?
int a;
printf("%d", maxvalue(a)); // 32767
unsigned int b;
printf("%d", maxvalue(b)); // 65535
所以基本上,当变量签名为INT时,函数返回INT_MAX
之类的值,当unsigned int时返回UINT_MAX等等。
答案 0 :(得分:9)
这样的功能不是由C标准库定义的。您可以尝试定义计算它的宏:
#define MAX_VALUE(a) (((unsigned long long)1 << (sizeof(a) * CHAR_BIT)) - 1)
使用时,请注意将其分配给足够大的类型。例如:
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#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
答案 1 :(得分:7)
您可以使用C11 type-generic expression:
轻松完成#define maxvalue(type) _Generic(type, int: INT_MAX, \
unsigned int: UINT_MAX)
这不是一个功能,但我认为它可以满足您的需求。这是一个简单的示例程序:
#include <stdio.h>
#include <limits.h>
#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位计算机。
答案 2 :(得分:3)
以下是我的库中用于类型的宏,而不是变量:
/* 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标准并不能保证它,并且它们肯定会在使用陷阱值初始化未初始化变量的实现上失败。
答案 3 :(得分:1)
可以使用ANSI C 89轻松完成:
#include<stdio.h>
#include<limits.h>
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);
虽然不太值得推荐。
祝你好运, 罗恩答案 4 :(得分:0)
不,标准C实现中不存在这样的功能。
答案 5 :(得分:0)
您无法创建执行此操作的函数,但您可以创建一些执行此操作的宏。
如果你有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;
/* ... */
答案 6 :(得分:0)
看起来我已经能够提出一个相对容易使用的宏SIGNED_VAR(VAR)
来测试给定的整数变量是否通过修改,比较和恢复变量的值来签名(所有这些都是仅适用于小于int
的类型,同时避免未定义的行为,特别是与签名溢出和序列点相关的类型。或者看起来如此。至少,gcc(使用-Wall
调用)并没有抱怨我在&&
和||
运算符之间做了一些疯狂的事情,尽管它不喜欢周围的同类事情。三元?:
运算符。
这个宏的优点是它应该与C89和C99编译器一起使用(1LL
可以替换为1L
而long long
可以替换为long
(当然,如果你的C89编译器没有来自C99的扩展"%ll"
类型,那么"%l"
和long long
)并且它也正确支持小于int
的类型({ {1}}和char
)。
一旦我们知道变量是否已签名,构造最小值和最大值是微不足道的,许多人已经说明了如何做到这一点。宏short
和VAR_MAX()
构造这些值并将它们作为最长的C99整数类型VAR_MIN()
返回。我选择返回签名类型,以避免在将无符号值转换为signed时出现潜在的溢出/ UB问题。由于返回的类型long long
不能直接将long long
(unsigned long long
)的最大值表示为有符号值,如果需要返回该值,则返回-1,之后返回转化为ULLONG_MAX
会产生unsigned long long
。你需要在这里小心一点。
这是丑陋的。希望,我没有错过任何一个错误。
哦,当然,预计在签名类型中支持2的补码值的整个非对称范围(例如min = -128,max = + 127)。
编辑:我忘了提及ULLONG_MAX
期望变量初始化。否则,读取它可能会导致未定义的行为。
SIGNED_VAR()
输出(ideone):
// file: IntVarMinMax.c
// compile: gcc -Wall -std=c99 -O2 IntVarMinMax.c -o IntVarMinMax.exe
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
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;
}