C 使用整型格式说明符而不是短int:为什么代码的行为是这样的?
当我为下面的程序提供4个整数作为输入时(比如a=10,b=20,d=30,e=40),它计算C 使用整型格式说明符而不是短int:为什么代码的行为是这样的?,c,memory,short,integer-overflow,format-specifiers,C,Memory,Short,Integer Overflow,Format Specifiers,当我为下面的程序提供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,
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);
}
#包括
void main()
{
短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);
}
这是未定义的行为,因此如果不详细分析实现,就无法给出“为什么”。但最有可能的是,编译器选择的变量布局导致在读入其他变量时,其中一些变量被破坏
使用我的编译器,在添加一行打印出a、b、d、e的地址后,我得到了输出
0
70
0x7fffa94d30ca
0x7fffa94d30c8
0x7fffa94d30c6
0x7fffa94d30c4
所以发生的事情很可能是
对a
的扫描在0x7fffa94d30ca
的低位字节中存储了10,在接下来的三个字节中存储了0(little endian机器),覆盖了堆栈中未分配给任何变量的两个字节,不幸的是没有致命的后果
对b
的扫描存储在0x7fffa94d30c8
处的字节中的20,将0扫描到接下来的三个字节,覆盖分配给a
的两个字节,因此将a
设置为0
对e
的扫描(巧妙地按照字母顺序和声明顺序完成)存储在0x7fffa94d30c4
处的字节中30个,并将0扫描到接下来的三个字节中,最后两个字节是d
分配的位置,但d
随后会被扫描,因此
对d
的扫描在0x7fffa94d30c6
的字节中存储了40,在接下来的三个字节中存储了0,用0覆盖b
添加c=a+b
的结果为0,因为扫描其他变量时两个变量都被覆盖;添加f=d+e
的结果为70,因为扫描后d
和e
都没有被覆盖
强制将c
分配到堆栈上,并通过将其地址打印到d
而不是b
覆盖c
而不是b
而不将其放在寄存器中,相应地,添加c=a+b
导致20
由于使用%d
格式说明符扫描short int
变量是未定义的行为,任何事情都可能发生,但如果编译器不利用UB,简单的解释将是正确的。%d
是用于读取int
的格式代码。如果short
小于int
,%hd
是读取short int
的正确格式代码,发生的情况是“%d”指示scanf读取和解析输入中的数字,将其转换为int,并将该int存储在相应的地址。通常,int是32位(四个字节),短int是16位(两个字节),尽管这可能有所不同
尽管scanf正在为每个“%d”写入四个字节,但您只为&a、&b、&e和&d中的每一个传递了两个字节。因此,其中两个字节指向正确的地址,另外两个字节指向&a、&b、&e和&d旁边的任何位置。它们中的一些相邻,并被散乱的字节覆盖
显然,这是一个非常糟糕的代码,永远不应该使用。您无法计算哪些变量将位于内存中其他变量的旁边。在许多平台上,short
的大小为2个字节,%d
格式规范告诉scanf()
目标有4个字节。因此,考虑当<代码> ScSff()/Cux>将4个字节写入一个只有2个可能副本的变量位置时会发生什么情况。