一段代码:
long rangeVar = 0;
rangeVar = atol(p_value);
if (rangeVar >= -2147483648 && rangeVar <= 2147483647)
编译时我得到:
警告:此十进制常量仅在ISO C90
中无符号
先谢谢
答案 0 :(得分:13)
十进制整数常量类型的规则在ISO C标准的1990年和1999年版本之间发生了变化。
在1990版本中,未加十进制的十进制整数常量类型是可以表示其值的int
,long int
或unsigned long int
中的第一个。 (C90没有long long
或unsigned long long
类型。
在1999和2011版本中,其类型是int
,long int
,long long int
之一;它永远不会是任何未签名的类型。
特定常量的类型(例如2147483648
)将根据您正在使用的编译器的整数类型的范围而变化。如果编译器的long
类型恰好是32位,那么如果编译器使用C90规则,则2147483648
将为unsigned long
类型,如果使用C11规则,则long long
类型为long long
类型(int
保证至少为64位)。编译器正在警告你。
您可以添加后缀以指定常量的类型 - 但是对于普通签名的U
没有后缀。您可以为unsigned int
添加L
,为long
添加UL
,为无符号长添加-2147483648
,依此类推。
重要的是要记住,2147483648
不是整数常量;而-2147483648
本身是一个整数常量,而unsigned long
是一个将一元减号运算符应用于该常量的表达式。在C90规则下,如果常量的类型为2147483648
,那么这是无符号一元减号,在无符号算术规则下产生值2147483648
。根据C99或C11规则,long long
可能是(带签名的)-2147483648
类型,否定它会产生long long
,同样类型为(-2147483647 - 1)
。
您有时会看到使用int
的代码来避免此问题;给定32位2147483647
,int
的类型为int
,表达式的结果会产生预期的{{1}}值而不会溢出。
当然,如果您的编译器对整数类型有不同的大小,这可能会变得更加复杂。
答案 1 :(得分:10)
是的,这是编译器无法很好地处理的一件事。问题是在编译期间,这是否定的数字2147483648,并且2147483648超出整数的范围。即使-2147483648也不会!
无论如何,要删除警告,您可以通过编写-2147483648LL
将常量转换为64位数。
但这有点过头了,所以首选的方法是使用INT_MIN
作为常数。但是,您需要包含<limits.h>
。
答案 2 :(得分:1)
是的,2147483648不是一个有效的正值,因为它在32位机器上超出了2的补码范围,所以他们只是试图警告你,在某些编译器上,这可能不会给你你想要的价值以现代方式处理否定。
我觉得值得添加另一个答案,指出如果你看看大多数limits.h实现,你会看到他们使用(-2147483647 - 1)
来解决这个问题。