我们知道signed char
只能包含从-128
到127
的值。
但是当我们运行下面的程序时,即使l输出超出了有符号字符的范围,也不会发生溢出。
#include <stdio.h>
int main()
{
char i = 60;
char j = 30;
char k = 10;
char l = (i*j)/k;
printf("%d ", l);
return 0;
}
l
的输出180
超出了char l
的范围,但我没有收到任何错误。
在其他情况下,如果我们采用相同的程序而不是算术函数,如果我们只是放l=180
并尝试打印它,那么我们得到错误的答案。
#include <stdio.h>
int main()
{
char i = 60;
char j = 30;
char k = 10;
char l = 180;
printf("%d ", l);
return 0;
}
我在第二个案例中得到的答案是-76
。
任何人都可以解释为什么?即使我实际上执行相同的事情,但我得到不同的结果。
编辑:
这是在int
而非char
所以在第一次我正在进行计算时,它将获取int中的所有值,在后面的部分我明确地将其称为char。
答案 0 :(得分:3)
C语言实际上无法对char
类型执行任何形式的计算。 char
是小整数类型,这意味着只要它作为表达式的一部分出现,它就会被隐式提升为int
。这称为整数提升或整数提升规则。
此外,还有另一个隐式类型转换回char
,因为您将结果存储在int
内,类型为char
。这称为左值转换:它将表达式的结果转换为指定对象的类型。
char l = (i*j)/k;
因此完全等同于
char l = (char)( (int)i * (int)j / (int)k );
由于所有算术都在类型int
上执行,因此没有溢出。结果180可能适合也可能不适合char
。
您应该避免将char
用于任何形式的算术,因为它具有实现定义的签名。在一个系统上,它可能被签名,-128到127,在另一个系统上它可能是无符号的,0到255.使用uint8_t
代替它,它是一种更好,更安全的类型。
答案 1 :(得分:1)
你确定你做过并测试了你在第一个片段中描述的内容吗?
如果它运行,溢出将按预期包装。
如果你这样做会有很大的不同
char l = (i*j)/k;
printf("%d ", l);
如果你做了
printf("%d ", (i*j)/k);
与第二种情况一样,编译器会推断使用int
作为输出,(结果无法显示在char内部而不显然),主要是因为中间计算是在int
而非char
。
此外,请考虑结果实际上适合unsigned char
,因此请检查此案例。
在你的情况下,我会开始考虑有问题的编译器的情况,但只有在我确定程序执行后应该做什么之后。
答案 2 :(得分:-2)
这是因为中间计算是使用int而不是使用char。 char可以是signed或unsigned,但是规范本身说char,signed char和unsigned char是3种不同的类型。
编辑:找出发生这种情况的原因:签名字符溢出,触发未定义的行为。这就是为什么你不能保持不变的原因。有符号整数类型(signed char,signed int,signed long)都会在溢出时触发未定义的行为。允许优化做任何事情,尽管它主要是忽略溢出的存在。