算术溢出因为C程序中有符号字符

时间:2016-07-04 13:54:28

标签: c output

我们知道signed char只能包含从-128127的值。 但是当我们运行下面的程序时,即使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。

3 个答案:

答案 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)都会在溢出时触发未定义的行为。允许优化做任何事情,尽管它主要是忽略溢出的存在。