C语言中的溢出和下溢

3

你们能向我解释一下 signed charunsigned char 的溢出和下溢是如何工作的吗?

int main () {
    signed char c;

    scanf("%d",&c);
    printf("%d\n",c);
    printf("%c\n",c);

return 0;
}

在这种情况下,如果使用scanf,给变量c赋值c=200,会发生溢出,并且第一个printf会显示出来。
第二个printf输出相同的 ASCII 符号 200...为什么呢?

9
scanf("%d",&c) 不是溢出或下溢,而是未定义行为。 - aschepler
进一步完善@aschepler所说,最有可能的结果是在c变量之后破坏3个字节,甚至可能会干扰返回地址本身。假设编译器(优化器)不会干扰这些东西,并且它的行为类似于手动直观翻译。 - Paul Stelian
3个回答

6

scanf 函数的 %d 参数只接收整数类型数据,如果使用其他类型数据会导致未定义行为。
因此,建议您按照以下方式处理:

int d;
scanf("%d", &d);
whatevertype c = (whatevertype)d;

然而,有符号整数溢出是未定义的。但如果您使用无符号类型,例如:
unsigned char c = (unsigned char)d;

那么c被保证是一个2的无符号char位数次幂的模等于d


你能解释一下未定义行为是什么,以及溢出的区别吗? - bigguy
@bigguy:你可能想看看这里:https://en.wikipedia.org/wiki/Undefined_behavior 或者这里https://dev59.com/sWMl5IYBdhLWcg3wa2bW#18420754 或者这里https://www.google.com/search?q=what+is+undefined+behaviour - alk

0

每个编译器都在特定的机器上运行,使用特定的硬件。

例如,我们的机器/处理器签名整数范围为16位。这意味着MAX_INT将是0x7fff十六进制值,即32767十进制值,MIN_INT将是0x8000十六进制值,即-32768十进制值。

大多数机器都有ALU控制寄存器,定义了在溢出情况下如何处理有符号整数。该寄存器通常具有饱和标志。

溢出示例: 如果设置了饱和标志,则在最后一个有符号整数ALU操作的结果大于MAX_INT的情况下,结果将被设置为MAX_INT。 例如,如果最后一次操作是将0x7ffe加上0x2,则结果将为0x7fff。

如果未设置饱和标志,则在最后一个有符号整数ALU操作的结果大于MAX_INT的情况下,结果可能会被设置为正确结果的低16位。在我们的例子中,0x7ffe + 0x2 = 0x8000,即最小整数。

对于无符号整数,编译器保证结果将根据C中无符号整数加法的定义。

下溢例子: 每个机器都有MIN_FLOAT定义。如果设置了饱和标志,则小于MIN_FLOAT的结果将被舍入为MIN_FLOAT。否则,结果将根据处理器的操作而定。(如果您感兴趣了解浮点表示和运算方面的术语,可以在互联网上进行搜索)。


0

在第一个printf语句中出现溢出的原因是因为您将char定义为signed char,如果您以%d格式打印它们,即整数,您将获得从0-127-1到-128的范围,因为我们都知道char在内存中占用一个字节,并通过将它们分配为有符号字符来将它们分成正值和负值,简单地说,无符号字节范围从0到255,因此有符号字符将为您提供从0到127和-1到-128的正值和负值范围。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接