当此代码:
// Print out the powers of 2 from 1 to 63.
#include <stdio.h>
int main() {
unsigned long long n = 64;
for (unsigned long long i = 1; i < n; i++) {
unsigned long long po2 = (1 << i);
printf("%llu) %llu/%0llX\n", i, po2, po2);
}
printf("Size of unsigned long long int: %ld.\n", sizeof(unsigned long long int));
}
运行时,左移位值高达30是正确的:
1) 2/2
2) 4/4
3) 8/8
...
28) 268435456/10000000
29) 536870912/20000000
30) 1073741824/40000000
但是,一旦 i == 31
(左移32位),结果不正确:
31) 18446744071562067968/FFFFFFFF80000000
32) 1/1
33) 2/2
34) 4/4
35) 8/8
36) 16/10
37) 32/20
...
61) 536870912/20000000
62) 1073741824/40000000
63) 18446744071562067968/FFFFFFFF80000000
Size of unsigned long long int: 8.
这是在64上运行的位机器和C标准状态:
整数促销是在每个操作数上执行的。类型
结果是晋升的左操作数。如果价值
正确的操作数为负或大于或等于宽度
在晋升的左操作数中,行为是不确定的。
请注意,在上述代码中,变量, i
和 n
都是64位整数,但是它们被视为32位整数一样!
When this code:
// Print out the powers of 2 from 1 to 63.
#include <stdio.h>
int main() {
unsigned long long n = 64;
for (unsigned long long i = 1; i < n; i++) {
unsigned long long po2 = (1 << i);
printf("%llu) %llu/%0llX\n", i, po2, po2);
}
printf("Size of unsigned long long int: %ld.\n", sizeof(unsigned long long int));
}
is run, left shift values up to 30 are correct:
1) 2/2
2) 4/4
3) 8/8
...
28) 268435456/10000000
29) 536870912/20000000
30) 1073741824/40000000
However, once i == 31
(a 32 bit left shift), the results are not correct:
31) 18446744071562067968/FFFFFFFF80000000
32) 1/1
33) 2/2
34) 4/4
35) 8/8
36) 16/10
37) 32/20
...
61) 536870912/20000000
62) 1073741824/40000000
63) 18446744071562067968/FFFFFFFF80000000
Size of unsigned long long int: 8.
This is run on a 64 bit machine, and the C Standard states:
The integer promotions are performed on each of the operands. The type
of the result is that of the promoted left operand. If the value of
the right operand is negative or is greater than or equal to the width
of the promoted left operand, the behavior is undefined.
Note that the variables, i
and n
, in the above code are both 64 bit integers, yet they are treated as if they were 32 bit integers!
发布评论
评论(2)
在以下行中查看
&lt;&lt;&lt;
操作:它的 左操作数 是什么?好吧,那是
int
文字, 1 ,int
type type will not 在这种情况下进行晋升 1 。因此,结果的类型将为int
,如您所引用的标准的摘录所指定的,并且该int
结果将转换为必需的>未签名的长长
类型…但是 溢出(未定义的行为)已经发生。要解决这个问题,请使用
ull
后缀:1 在
href =“ https://en.cppreference.com/w/c/language/operator_arithmetic” rel =“ nofollow noreferrer”>此cppReference page
(大胆的重点):
Look at the
<<
operation in the following line:What is its left operand? Well, that is the
int
literal,1
, and anint
type will not undergo promotion, in that context1. So, the type of the result will beint
, as specified in the extract from the Standard that you cited, and thatint
result will be converted to the requiredunsigned long long
type … but after the overflow (undefined behaviour) has already happened.To fix the issue, make that literal an
unsigned long long
, using theuLL
suffix:1 Some clarity on the "context" from this cppreference page (bold emphasis mine):
阿德里安·摩尔是正确的。修订的代码:
作品。
Adrian Mole is correct. The revised code:
works.