AC左移动异常在未签名的长长ints中

发布于 2025-01-27 00:39:31 字数 1111 浏览 3 评论 0 原文

当此代码:

// 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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

雪落纷纷 2025-02-03 00:39:31

在以下行中查看&lt;&lt;&lt; 操作:

unsigned long long po2 = (1 << i);

它的 左操作数 是什么?好吧,那是 int 文字, 1 , int type type will not 在这种情况下进行晋升 1 。因此,结果的类型将为 int ,如您所引用的标准的摘录所指定的,并且该 int 结果将转换为必需的>未签名的长长类型…但是 溢出(未定义的行为)已经发生。

要解决这个问题,请使用 ull 后缀:

unsigned long long po2 = (1uLL << i);

1 href =“ https://en.cppreference.com/w/c/language/operator_arithmetic” rel =“ nofollow noreferrer”>此cppReference page (大胆的重点):

Shift Operators


首先,在每个操作数上单独进行整数促销
其他二进制算术运算符,它们都执行通常的算术
转换)。结果的类型是 lhs 之后的类型
促销。

Look at the << operation in the following line:

unsigned long long po2 = (1 << i);

What is its left operand? Well, that is the int literal, 1, and an int type will not undergo promotion, in that context1. So, the type of the result will be int, as specified in the extract from the Standard that you cited, and that int result will be converted to the required unsigned long long type … but after the overflow (undefined behaviour) has already happened.

To fix the issue, make that literal an unsigned long long, using the uLL suffix:

unsigned long long po2 = (1uLL << i);

1 Some clarity on the "context" from this cppreference page (bold emphasis mine):

Shift Operators


First, integer promotions are performed, individually, on each operand (Note: this is unlike
other binary arithmetic operators, which all perform usual arithmetic
conversions). The type of the result is the type of lhs after
promotion.

我是有多爱你 2025-02-03 00:39:31

阿德里安·摩尔是正确的。修订的代码:

// Print out the powers of 2 from 1 to 63. 
#include <stdio.h>

int main() {
  unsigned long long n = 64,
                     one = 1;
  for (unsigned long long i = 1; i < n; i++) {
    unsigned long long po2 = (one << i);
    printf("%llu) %llu/%0llX\n", i, po2, po2);
  }
  printf("Size of unsigned long long int: %ld.\n", sizeof(unsigned long long int));
}

作品。

Adrian Mole is correct. The revised code:

// Print out the powers of 2 from 1 to 63. 
#include <stdio.h>

int main() {
  unsigned long long n = 64,
                     one = 1;
  for (unsigned long long i = 1; i < n; i++) {
    unsigned long long po2 = (one << i);
    printf("%llu) %llu/%0llX\n", i, po2, po2);
  }
  printf("Size of unsigned long long int: %ld.\n", sizeof(unsigned long long int));
}

works.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文