我知道,C标准很好地定义(unsigned)-1
必须产生2 ^ n-1,i。即一个无符号整数,其所有位都已设置。 (uint64_t)-1ll
也是如此。但是,我在C11标准中找不到指定如何解释(uint64_t)-1
的内容。
所以,问题是:C标准中是否有任何保证,以下哪项适用?
(uint64_t)-1 == (uint64_t)(unsigned)-1 //0x00000000ffffffff
(uint64_t)-1 == (uint64_t)(int64_t)-1 //0xffffffffffffffff
答案 0 :(得分:14)
是。参见C11 6.3.1.3有符号和无符号整数:
1当整数类型的值转换为_Bool以外的另一个整数类型时,如果该值可以用新类型表示,则它将保持不变。
2否则,如果新类型是无符号的,则通过重复加或减一个可以在新类型中表示的最大值来转换该值,直到该值在新类型的范围内为止。 > 60)
3否则,新类型已签名且值无法在其中表示;结果是实现定义的,或者引发实现定义的信号。
60)规则描述了数学值的算术,而不是给定表达式的值。
情况2适用,因此-1减少模0x10000000000000000以产生0xffffffffffffffff。
答案 1 :(得分:5)
表达式1
和-1
的类型为int
。转换为uint64_t
时,加上或减去2 n 直到该值在范围内的原则适用,因此结果总是2 n -1,在这种情况下,n = 64。因此,(uint64_t)-1
总是2 64 -1 ..
表达式(int64_t)-1
的计算结果为-1,因此相同的推理适用于表达式(uint64_t)(int64_t)-1
,它也总是计算为2 64 -1。
另一方面,(unsigned)-1
是类型unsigned int
的正值,可能是2 16 -1,2 32 -1 ,2 64 -1或其他各种值,具体取决于编译平台。转换为uint64_t
时,这些值可能不会产生2 64 -1。
答案 2 :(得分:2)
我猜你是在写(uint64_t)-1
而不是-1ULL
,因为你不想对unsigned long long
的大小做出假设?如果是这样,那很好。但是,有一个替代方案尚未被提及(并且实际上没有回答你的问题),但可以通过侧面提出问题来节省很多担心:
一个好习惯是始终使用UINT64_C(x)
代替(uint64_t)x
。这是<stdint.h>
中定义的宏,可根据需要自动附加U
,UL
或ULL
。因此,UINT64_C(-1)
会解析为-1U
,-1UL
或-1ULL
,具体取决于您的目标。这保证始终正常工作。
请注意(uint64_t)x
实际上甚至无法正常工作。例如,
(uint64_t)2147483648 // RISKY
在某些编译器上生成警告,因为值2147483648(2 ^ 31)太大而无法进入32位整数,并且以下内容甚至无法远程工作:
(uint64_t)1000000000000000000 // RISKY
但是,如果你改用UINT64_C()
,那么一切都很好:
UINT64_C(2147483648) // GOOD
UINT64_C(1000000000000000000) // GOOD
UINT64_C(-1) // GOOD
注意:
_C
后缀代表“常量”。<stdint.h>
中,对于有符号和无符号值,还有8位,16位和32位版本。UINT64_MAX
。答案 3 :(得分:-5)
这是一个可以用几行代码回答的问题。
#include <stdio.h>
main()
{
int x;
unsigned int y;
x = -1;
printf("\n0x%08x", x);
y = (unsigned int) -1;
printf("\n0x%08x", y);
}
在Eclipse / Microsoft C编译器上运行此代码会产生:
0xffffffff
0xffffffff
类似的程序可以显示uint64_t
产生的内容。
最后,如果您了解计算机如何使用2的补数来添加数字,那么您将理解-1对于任意位数(8,32,64等)的单词总是对于每个字节的所有ff都是单词/双字等等。