5
#include<stdio.h>
int main(void)
{
  char c = 0x80;
  printf("%d\n", c << 1);
  return 0;
}

-256在这种情况下输出。如果我写c << 0,那么输出是-128.

我不明白这段代码背后的逻辑。

4

5 回答 5

18

char可能在您的平台上签名,在这种情况下0x80表示 -128(假设二进制补码)。

当 achar与运算符一起用作操作数时<<,它被提升为int(仍为 -128)。因此,当您应用左移时,您会得到 -256。从技术上讲,转移负值是实现定义的未定义,但您看到的是典型行为。

于 2010-10-22T23:29:43.250 回答
6

您的出发点已经有问题:

char c = 0x80;

如果(在您的情况下似乎)char是有符号类型,则您将整数常量分配给128仅保证将值保存到127. 然后,您的编译器可能会选择为您提供一些实现定义的值(-128在您的情况下我猜)或发出范围错误。

然后你对该负值进行左移。这给出了未定义的行为。总的来说,您有几个实现定义的选择以及决定结果的未定义行为:

  • 的签名char
  • 选择如何转换128signed char
  • 的宽度char
  • 的符号表示int(有三种可能)
  • 关于如何实现(或不)负左移的选择int

查看所有这些案例并了解不同的结果可能是一个很好的练习。

总结一些建议:

  • 选择一个合适的常量来初始化一个变量
  • 不要用普通的算术char
  • 不要对有符号类型进行左移
于 2010-10-23T08:59:36.983 回答
3

c被分配0x80。假设 8 位字节,其二进制表示的值为10000000. 显然,在您的平台上,char是签名类型。因此,0x80(ie 10000000) 对应于 -128。

<<应用于一个char值时,它会被提升int并保留符号。因此,当向左移动一次时,使用 32 位整数,它变为11111111111111111111111100000000(二进制补码),即 -256。

于 2010-10-22T23:35:03.820 回答
1

只是一个旁注。从自下而上的角度来看,按位移位(和掩码)基于架构的字长(以位表示)。一个词的长度,因建筑而异。

请参阅此 Wiki 页面以了解按架构划分的字长

如果知道目标体系结构的字长,则可以使用位移来进行乘法和除法(在某些情况下),比使用操作数更快。

有关移位的有趣图表,请参见此 Wiki 页面

由于位移代码依赖于体系结构,因此不能假设特定的位移代码在不同体系结构之间以相同的方式工作。然而,一旦人们熟悉了不同架构的不同字长的概念,移位就变得不那么神秘和更可预测了。

值得庆幸的是,今天我们有 8、16、32 和 64 位字长,并且只有 8 位字符长度。在古代计算时代,架构可能有 12 位、15 位或 23 位字长(等等,令人作呕)。

于 2010-10-23T02:36:51.343 回答
0

我想知道为什么您的编译器没有抱怨 0x80 不适合 char 的警告,在您的平台上它只能表示从 -0x80 到 0x7F 的值。

试试这段代码:

 #include <stdio.h>
 #include <limits.h>
 #include <stdlib.h>

 int main() {
      printf("char can represent values from %d to %d.\n", CHAR_MIN, CHAR_MAX);
      return EXIT_SUCCESS;
 }

您的情况称为溢出。

于 2010-10-23T00:46:32.923 回答