为什么将无符号长整型设置为2^64-1时,GCC会发出警告?

3

C标准规定long int至少为4个字节,在我的系统上是8个字节。

这意味着我可以在long中存储值高达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

}

如果我使用263-1 (9223372036854775807),则会无警告编译(正如预期的那样, 263-1将适合于signed long int)。
在一个项目中,我需要在unsigned long中获得最大值,我发现(9223372036854775807 << 1) + 1将不会引发这个警告。我的老师建议我可以使用limits.h中定义的ULONG_MAX,这样就没有警告了。
为什么我不能在显式声明时不出现警告而进行隐式转换?

2
你需要将字面量指定为无符号长整型。18446744073709551615UL - Christian Gibbons
尝试在您的数字常量后添加 ul - Ctx
3个回答

6
根据C标准,没有后缀的十进制常量的类型是int、long int或long long int,具体取决于可以表示该值的第一个类型。在您的C实现中,没有一个类型可以表示18446744073709551615,因为它太大了。
为了适应您,编译器将其类型设置为unsigned long。从技术上讲,这不符合C标准,因此编译器会向您发出警告。
在这种情况下,没有造成任何损害,因为您将该值赋给了unsigned long。但是,在某些情况下,使用错误的类型可能会导致问题,因此通常应附加后缀以确保它们与预期的用法匹配。在这种情况下,u就足够了;与无后缀类型一样,编译器将根据数字的大小和类型的能力决定是否使用unsigned int、unsigned long int或unsigned long long int。

5

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

请使用a = 18446744073709551615U;来明确声明。


我明白了 - 它是在说我输入的数字已经被隐式转换了,而不是我声明的变量。 - Tim
应该不是 ull 吗?或者至少是 ul 吧? - Nikos C.
2
@NikosC:在这种情况下,不需要使用ulull。 C标准规定十进制常量的类型会有所调整以适应其值。如果使用了u后缀,则类型将是可以表示该值的unsigned intunsigned long intunsigned long long int中的第一个。 - Eric Postpischil
1
@NikosC。请查看我的答案中的整数字面量促销表。 - Petr Skocik

4

看看这个标准(6.4.4.1p5)中的漂亮表格

integer constant promotion table from the standard

这段文字讲解了整数字面值如何适应整数类型。基本上,由于您的字面值是十进制且没有后缀,它会尝试适应以下类型:
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位,通常情况下是这样)。

或者,您可以通过转换为八进制或十六进制文字来关闭警告:

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,因此请勿这样做。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接