为什么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标准,没有后缀的十进制常量的类型是intlong intlong long int ,特别是足以表示该值的第一个。 在你的C实现中,没有一个可以代表18446744073709551615,因为它太大了。

为了适应您,编译器使其类型为unsigned long 。 从技术上讲,这不符合C标准,因此编译器会警告您。

在这种情况下,不会造成任何伤害,因为您要将值分配给unsigned long 。 但是在某些情况下,使用错误的类型会导致问题,因此通常应该为这些常量添加后缀,以确保它们与预期的使用方式相匹配。 在这种情况下, u就足够了; 与非混合类型一样,编译器将决定是使用unsigned intunsigned long int还是unsigned long long int具体取决于数量的大小和类型的function。

你明确地声明了它,但没有U,这会使它无符号。 由于此值没有带符号的整数常量,因此它隐式地使其无符号,为您提供最好使其显式化的信息。

a = 18446744073709551615U;

从标准(6.4.4.1p5)中查看这个花哨的表格 :

标准的整数常量升级表

这解释了整数文字如何适合整数类型。

基本上,因为您的文字是十进制的并且没有后缀,所以它会尝试适合以下类型:

 int long int long long int 

因为它不适合long long int ,所以你得到了警告。

如果添加Uu )后缀(或ULUL或小写变体):

 unsigned long a = 18446744073709551615U; 

你不会遇到这个问题,因为你会转到推广序列:

 unsigned int unsigned long int unsigned long long int 

(或ULUL的相应子集),文字将适合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来调用未定义的行为,无论是否生成警告。