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
}
如果我使用2 63 -1(9223372036854775807),它会编译而没有警告(正如预期的那样 - 2 63 -1将适合{{1} })。
对于项目,我需要在signed long int
中获得最大值,并且我发现unsigned long
不会引发此警告。我的老师然后建议我可以使用(9223372036854775807 << 1) + 1
中定义的ULONG_MAX
,但这没有给出任何警告。
为什么我不能在没有警告声明它被隐式转换的情况下执行此操作 - 当我明确声明它时?
答案 0 :(得分:5)
根据C标准,没有后缀的十进制常量的类型是int
,long int
或long long int
,特别是足以表示该值的第一个。在你的C实现中,没有一个可以代表18446744073709551615,因为它太大了。
为了适应您,编译器正在进行类型unsigned long
。从技术上讲,这不符合C标准,因此编译器会警告您。
在这种情况下,不会造成任何伤害,因为您要将值分配给unsigned long
。但是在某些情况下使用错误的类型会导致问题,因此通常应该为这些常量添加后缀,以确保它们与预期的使用方式相匹配。在这种情况下,u
就足够了;与非混合类型一样,编译器将决定是使用unsigned int
,unsigned long int
还是unsigned long long int
,具体取决于数量的大小和类型的功能。
答案 1 :(得分:4)
你明确地声明了它,但没有U,这会使它无符号。由于没有带有此值的带符号整数常量,因此它隐式地使其无符号,为您提供最好使其明确的信息。
使用a = 18446744073709551615U;
执行此操作。
答案 2 :(得分:3)
查看此fancy table from the standard (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个可用位)。
或者,您可以通过切换到八进制或十六进制文字来关闭警告:
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来调用未定义的行为。