为什么GCC在将无符号长整数设置为2 ^ 64-1时发出警告?
C标准规定long int
至少为4个字节 – 在我的系统上它是8个字节。
这意味着我可以存储长度为2 ^ 63 -1且unsigned long
2 64 -1的值。
但是,当使用-Wall
标志编译以下代码时,它会发出警告[Wimplicitly-unsigned-literal]
:
int main (int argc, char ** argv) { unsigned long a; a = 18446744073709551615; // 2^64-1 }
如果我改为使用2 63 -1(9223372036854775807),则编译时没有警告(正如预期的那样 – 2 63 -1将适合signed long int
)。
对于一个项目,我需要在unsigned long
中具有unsigned long
,并且我发现(9223372036854775807 << 1) + 1
不会引发此警告。 然后我的老师建议我可以使用limits.h
定义的ULONG_MAX
,但没有给出任何警告。
为什么我不能在没有警告声明它被隐式转换的情况下这样做 – 当我明确地声明它时?
根据C标准,没有后缀的十进制常量的类型是int
, long int
或long long int
,特别是足以表示该值的第一个。 在你的C实现中,没有一个可以代表18446744073709551615,因为它太大了。
为了适应您,编译器使其类型为unsigned long
。 从技术上讲,这不符合C标准,因此编译器会警告您。
在这种情况下,不会造成任何伤害,因为您要将值分配给unsigned long
。 但是在某些情况下,使用错误的类型会导致问题,因此通常应该为这些常量添加后缀,以确保它们与预期的使用方式相匹配。 在这种情况下, u
就足够了; 与非混合类型一样,编译器将决定是使用unsigned int
, unsigned long int
还是unsigned long long int
具体取决于数量的大小和类型的function。
你明确地声明了它,但没有U,这会使它无符号。 由于此值没有带符号的整数常量,因此它隐式地使其无符号,为您提供最好使其显式化的信息。
a = 18446744073709551615U;
。
从标准(6.4.4.1p5)中查看这个花哨的表格 :
这解释了整数文字如何适合整数类型。
基本上,因为您的文字是十进制的并且没有后缀,所以它会尝试适合以下类型:
int long int long long int
因为它不适合long long int
,所以你得到了警告。
如果添加U
( u
)后缀(或UL
或UL
或小写变体):
unsigned long a = 18446744073709551615U;
你不会遇到这个问题,因为你会转到推广序列:
unsigned int unsigned long int unsigned long long int
(或UL
和UL
的相应子集),文字将适合unsigned long int
(如果这确实是第一个无符号类型,通常不少于64个可用位)。
或者,您可以通过切换到八进制或hex文字来关闭警告:
unsigned long a = 0xFFFFFFFFFFFFFFFF; unsigned long octal_a = 01777777777777777777777;
至于这些促销顺序是:
int unsigned int long int unsigned long int long long int unsigned long long int
根据链表,它再次允许它们适合第一个64位大的无符号类型(通常是unsigned long int
)。
你绝对不应该做的是:
(9223372036854775807 << 1) + 1 //don't do this!
因为这会通过破坏6.5.7p4来调用未定义的行为,无论是否生成警告。