当我提供以下4个整数作为输入的程序时(比如a = 10,b = 20,d = 30,e = 40),它会计算c = a + b = 0
和f = d + e = 70
。
我知道这种不寻常的行为是因为我对short int使用了错误的格式说明符,但这究竟发生了什么?为什么最后两个输入的总和是正确的,前两个数字的总和总是= 0?
#include<stdio.h>
void main()
{
short int a, b, c, d, e, f;
scanf("%d%d%d%d", &a, &b, &e, &d);
c = a + b;
f = d + e;
printf("%d\n%d\n", c, f);
}
答案 0 :(得分:3)
这是未定义的行为,因此如果不详细分析实现,就没有“为什么”。但最有可能的是,编译器选择的变量布局导致其中一些变量在读入其他变量时被破坏。
使用我的编译器,在添加一行打印出a, b, d, e
的地址后,我得到了输出
0
70
0x7fffa94d30ca
0x7fffa94d30c8
0x7fffa94d30c6
0x7fffa94d30c4
所以发生的事情可能是¹
a
的低位字节中扫描到0x7fffa94d30ca
存储10,在接下来的三个字节(小端机器)中扫描0,覆盖未分配的堆栈的两个字节任何变数,不幸的是没有致命的后果,b
存储在0x7fffa94d30c8
字节中的20,将0写入接下来的三个字节,覆盖为a
分配的两个字节,因此将a
设置为0,e
(巧妙地按字母顺序和声明顺序完成)在0x7fffa94d30c4
的字节中存储30,在接下来的三个字节中存储0,其中最后两个是{{1已分配,但之后会扫描d
,所以d
存储在d
字节中的40和接下来三个字节中的0,用0覆盖0x7fffa94d30c6
,b
结果为0,因为在扫描到其他变量时两个变量都被覆盖,而c = a + b
添加结果为70,因为f = d + e
和d
都不是扫描后覆盖。强制e
在堆栈上分配,而不是通过打印出来的地址放在寄存器中,这里扫描到c
覆盖d
而不是{{1}相应地,添加c
导致了20。
¹由于使用b
格式说明符扫描到c = a + b
变量是未定义的行为,所以可能发生任何事情,但如果编译器没有尽力利用UB,那么简单的解释将是正确的。
答案 1 :(得分:3)
"%d"
是用于读取int
的格式代码。如果short
小于int
,则"%hd"
是阅读short int
的正确格式代码。
答案 2 :(得分:1)
正在发生的事情是“%d”指示scanf从输入中读取和解析数字,将其转换为int,并将该int存储在相应的地址中。通常,int是32位(四个字节),而short int是16位(两个字节),尽管这可能会有所不同。
尽管scanf为每个“%d”写入四个字节,但是对于&amp; a,&amp; b,&amp; e和&amp; d中的每一个,它只传递了两个字节。因此,两个字节转到正确的地址,另外两个转到&amp; a,&amp; b,&amp; e和&amp; d旁边的任何一个。它们中的一些彼此相邻并被杂散字节覆盖。
显然,这是非常破碎的代码,永远不应该使用。你不能指望哪些变量将与内存中的其他变量相邻。