我的代码中有一个问题,在C语言中按位移位,我将其归结为以下示例:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>

int main(int argc, char **argv)
{
  char a = 1;
  int i=0;
  uint64_t b;
  for(i=0; i<64; i++)
  {
    b=0;
    printf("i=%d\n", i);
    b = (a<< ((uint64_t) i));
    printf("%" PRIu64 "\n", b);
  }
  return 0;

}

由于这个MWE中不明显的原因,我想从中产生2到2^63的能量它失败是因为发生了一些奇怪的事情,因为a不是char明显的解决办法是
b = ((uint64_t)a<< ((uint64_t) i))

为了理解到底发生了什么,我在上面写了一个MWE示例,从中我得到了输出(部分显示):
i=30
1073741824
i=31
18446744071562067968
i=32
1
i=33
2

现在我想知道如何解释从a跳到uint64_t的过程怎么会在i=30时再次成为1呢?
如果有兴趣的话,我使用gcc(i=31)编译了上面的代码

最佳答案

很多答案已经指出你的代码有未定义的行为因此,对所发生的事情进行推理(因为任何事情都可能发生……)通常是没有意义的。
但是。。。。有时候不管怎样做都是很有趣的-记住这是纯粹的猜测,不能保证是正确的和高度依赖于系统的。。。。
所有的免责声明都准备好了。。。
奇数18446744071562067968从哪里来?
让我们假设32位int,并注意到由于整数提升,您的char a = 1;也可以int a = 1;所以我们可以写:

int a = 1;
int as = a << 31;  // Undefined behavior here as 1*2^31 can't be stored in 32 bit int
uint64_t b = as;
printf("%" PRIu64 "\n", b);

输出:
18446744071562067968

六羟甲基三聚氰胺六甲醚。。。。我们有神秘的18446744071562067968但是为什么?
再打印一次:
int a = 1;
int as = a << 31;  // Undefined behavior here
uint64_t b = as;
printf("%d\n", as);
printf("%" PRIu64 "\n", b);

输出
-2147483648
18446744071562067968

所以as是阴性的所以我们真的做到了:
uint64_t b = -2147483648;

因为b是无符号的,所以上面的计算如下:
uint64_t b = UINT64_MAX + 1 - 2147483648;  // which is 18446744071562067968

现在我们知道18446744071562067968是从哪里来的毕竟没那么神秘。
但这留下了另一个问题-为什么as是阴性的?
六羟甲基三聚氰胺六甲醚。。。。再打印一次:
int a = 1;
int as = a << 31;  // Undefined behavior here
uint64_t b = as;
printf("%d\n", as);
printf("%x\n", as);  // Print as in hex
printf("%" PRIu64 "\n", b);

输出:
-2147483648
80000000
18446744071562067968

所以在hex中as80000000实际上是a1左移31次所以处理器只是做了我们要求的,也就是说,1 << 31它在C标准中没有定义,但是您/我的处理器就是这样实现的-其他机器可能会做其他事情。
80000000作为32位2的补码是-2147483648,因此我们知道为什么as是负的。

09-05 01:37