C语言中的字符乘法

C语言中的字符乘法,c,char,multiplication,C,Char,Multiplication,我有这样一个代码: #include <stdio.h> int main() { char a=20,b=30; char c=a*b; printf("%c\n",c); return 0; } #包括 int main() { 字符a=20,b=30; 字符c=a*b; printf(“%c\n”,c); 返回0; } 该程序的输出为X 如果作为字符值溢出的a*b=600位于-128和127之间,那么该输出如何可能?首先,行为在这里定义。char可以是uns

我有这样一个代码:

#include <stdio.h>
int main()
{
  char a=20,b=30;
  char c=a*b;
  printf("%c\n",c);
  return 0;
}
#包括
int main()
{
字符a=20,b=30;
字符c=a*b;
printf(“%c\n”,c);
返回0;
}
该程序的输出为X


如果作为字符值溢出的a*b=600位于-128和127之间,那么该输出如何可能?

首先,行为在这里定义。
char
可以是
unsigned char
signed char
,因此它可以将
0
保存到
255
-128
保存到
127
,假设
char\u位==8


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

首先,看起来您的
无符号字符的范围是0到255。
你说得对

600 - 256 - 256 = 88

这只是“X”的ASCII码。

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

无论如何,乘法是以
int
的形式进行的,结果转换为
char

如果该值不适合“较小”类型,则它是为
有符号字符
的实现方式定义的。到目前为止,大多数(如果不是全部的话)实现都只是简单地切断高位

对于
无符号字符
,标准实际上要求(短暂地)切割高位

因此:

(假设为8位
char

有关更多详细信息,请参见链接及其周围段落

注意:如果启用编译器警告(始终建议),则应该为分配获得截断警告。这可以通过显式强制转换来避免(只有当您确实确信所有含义时)。gcc选项为
-Wconversion
如果签名了
char
,则此代码将导致未定义的行为

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

引用6.3.1.3有符号和无符号整数:

3否则,新类型已签名,且无法在其中表示值;要么 结果是定义了实现或发出了定义了实现的信号


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

关于溢出,您是对的,但不是转换(必须自己查找以确保:-)顺便说一句:您应该更新您的引用。这不是当前的标准。+1从不知道“由于整数提升,乘法以
int
的形式进行,结果转换为
char
”。我认为如果由于溢出而
char
签名
,代码将调用未定义的行为。@CoolGuy:我必须亲自查看标准以进行转换。但一般来说,所有“较小”的整数首先被提升为
int
unsigned
(后者仅当
unsigned char
unsigned int
具有相同的宽度时,类似于
short
,这一点更为重要)。大多数实现的效果基本相同,但是正确配置的编译器(例如gcc:
-Wconversions
)应该警告截断。@CoolGuy:“未定义的行为”意味着它可以随心所欲,包括(但不限于)忽略不适合
字符的高位(这是大多数实现所做的)。@IanAbbott:我认为UB的意思并不奇怪,但有损转换实际上不是UB,因此,
char
“overflow”(语义溢出,但技术上是转换/截断)和
int
(true)的标准表现不同溢出。类型强制的一种恶行。详细信息:没有发生溢出。
a
b
在乘法之前被转换为
int
,并且
600
int
范围内。@chux嗯,
0x258
不适合于泛型
char
,但我想这不是所谓的溢出…不会编辑帽子。@cad:这是一个截断。通常用于大多数(所有?)实现,但不是由有符号整数的标准定义的。没有发生溢出。确实发生了实现定义的600到a
char
的转换。这实际上取决于体系结构。如果在此处发生溢出,则不取决于体系结构。
a
b
首先升级为
int
无符号
(取决于实现)。600的产品已生产(不依赖于体系结构)正如这个答案所断言的,没有溢出。600到
char
的转换是由实现定义的。我可能弄错了,但我不确定如果使用8位MCU,它们是否升级为int。它们必须始终升级为int,否则编译器不符合标准。在实际情况下,您不需要升级为int以获得更广泛的应用结果,由于大多数体系结构都有加宽的乘法,所以您需要一条8x8->16 mul指令
(int)20 * (int)20 -> (int)600 -> (char)(600 % 256) -> 88 == 'X'