C 中的字符乘法

Char multiplication in C

我有这样的代码:

#include <stdio.h>
int main()
{
  char a=20,b=30;
  char c=a*b;
  printf("%c\n",c);
  return 0;
}

这个程序的输出是X .

如果 a*b=600 由于 char 值介于 -128 和 127 之间而溢出,这个输出怎么可能?

首先,这里的行为是实现定义的。一个 char 可能是 unsigned charsigned char,因此它可能能够保持 0255-128127, 假设 CHAR_BIT == 8.

600 的十进制为 0x258。发生的事情是存储最低有效的八位,值为 0x58 a.k.a。 X 在 ASCII 中。

首先,看起来您的 unsigned char 范围从 0 到 255。 关于溢出,你是对的。

600 - 256 - 256 = 88

这只是'X'的ASCII码。

char 是有符号的还是无符号的由实现定义。无论哪种方式,它都是一个整数类型。

无论如何,由于integer promotions,乘法按int完成,结果转换为char

如果该值不适合 "smaller" 类型,它是为 signed char 定义的实现方式。大多数(如果不是全部)实现只是简单地切断了高位。

对于 unsigned char,标准实际上要求(简要地)切割高位。

所以:

(int)20 * (int)20 -> (int)600 -> (char)(600 % 256) -> 88 == 'X'

(假设 8 位char)。

有关详细信息,请参阅 link 及其周围的段落。

注意:如果您启用编译器警告(一如既往的建议),您应该会收到一个赋值的截断警告。这可以通过显式强制转换来避免(仅当您 确实 确定所有含义时)。 gcc 选项是 -Wconversion.

如果 char 已签名,此代码将导致未定义的行为。

我认为有符号整数溢出是未定义的行为,但转换为更小的类型是实现定义的。

引自N1256 6.3.1.3 有符号和无符号整数:

3 Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.

如果该值被简单地截断为 8 位,则 (20 * 30) & 0xff == 0x58 和 0x58 是 X 的 ASCII 码。因此,如果您的系统执行此操作并使用 ASCII 代码,则输出将为 X.