我是C初学者,我对C答案集中的以下示例感到困惑。
在系统中查找unsigned long long大小的一种方法是键入:
printf("%llu", (unsigned long long) ~0);
我不知道为什么这种语法有效?
在我的系统上,int
为32位,long long
为64位
我所期望的是,由于0
是一个整数类型的常量,~0
计算一个32位整数的否定,然后由强制转换运算符转换为unsigned long long
。结果应该给出2 32 - 1。
不知怎的,看起来~
运算符已经知道它应该在64位上运行?
编译器是否将此指令解释为printf("%llu", ~(unsigned long long)0);
?由于演员和~
具有相同的优先权,这听起来并不合适。
答案 0 :(得分:13)
不知怎的,看起来〜运算符已经知道它应该在64位上运行?
这不是~
运算符,而是演员。以下是根据标准完成整数转换的方法:
6.3.1.3有符号和无符号整数
- 当整数类型的值转换为_Bool以外的另一个整数类型时,如果该值可以用新类型表示,则它将保持不变。
- 否则,如果新类型是无符号的,则通过重复地添加或减去一个可以在新类型中表示的最大值来转换该值,直到该值在新类型的范围内。
- 否则,新类型已签名且值无法在其中表示;结果是实现定义的,或者引发实现定义的信号。
签名int
~0
的值对应于具有负值的二进制补码表示的系统上的-1
。它不能用unsigned long long
表示,因此第一个要点不适用。
第二个项目符号确实适用:新类型未签名,因此MAX
的{{1}}已添加到unsigned long long
一次,以便将结果纳入-1
的范围内。这与将unsigned long long
符号扩展到64位具有相同的效果。
答案 1 :(得分:5)
0
的类型为int
,而不是unsigned int
。因此~0
(在使用2的补码整数表示的机器上,这是今天使用的全部)是-1,而不是2 32 - 1。
假设64位unsigned long long
,(unsigned long long) -1
为-1
模2 64 ,即2 64 - 1。
答案 2 :(得分:0)
0
是int
~0
仍为int
,即值-1
。
将int
投射到unsigned long long
只是为了匹配printf期望的转换类型llu
。
然而,-1扩展无符号long long的值应为0xffffffff为4字节int和0xffffffffffffffff为8字节int。
答案 3 :(得分:0)
根据N1570委员会草案:
6.5.3.3 Unary arithmetic operators
- 〜运算符的结果是它的按位补码 (提升)操作数(也就是说,结果中的每个位都是设置的 如果未设置转换后的操作数中的相应位)。该 对操作数执行整数提升,结果为 推广类型。如果提升的类型是“无符号类型,则 表达式~E等于其中可表示的最大值 型号减去E“。
醇>§6.2.6.2 Language 45
(补充)。其中的哪一个适用于实现定义,以及符号位为1且所有值位为零的值(对于前两个),还是符号位和所有值位1(对于'补码),是陷阱表示或正常值。在符号和幅度以及1的补码的情况下,如果该表示是正常值,则称为负零。
因此,代码的行为:
printf("%llu", (unsigned long long) ~0);
在某些机器上是实现定义的和未定义的 - 不是按照预期的 - 取决于机器中整数的内部表示。
根据6.5.3.3节,批准的编写代码的方式是:
printf("%llu", (unsigned long long) ~0u);
此外,~0u
的类型是unsigned int,当您将其转换为unsigned long long int
格式字符串为llu
时。使用格式字符串~0u
打印%u
。
要了解类型转换的基本概念,您可以阅读:What exactly is a type cast in C/C++?