【问题标题】:Using integer format specifier instead of short int: Why does the code behave like this?使用整数格式说明符而不是短整数:为什么代码会这样?
【发布时间】:2012-07-03 18:58:30
【问题描述】:

当我为以下程序提供 4 个整数作为输入(例如 a = 10、b = 20、d = 30、e = 40)时,它会计算 c = a + b = 0f = 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);
}

【问题讨论】:

  • 在许多平台上,short 的大小为 2 个字节,%d 格式规范告诉 scanf() 目标有 4 个字节。所以考虑一下当scanf() 将 4 个字节写入一个只有 2 个字节的变量位置时会发生什么。

标签: c memory short integer-overflow format-specifiers


【解决方案1】:

"%d" 是用于读取int 的格式代码。如果short 小于int,则"%hd" 是读取short int 的正确格式代码。

【讨论】:

    【解决方案2】:

    这是未定义的行为,因此如果不详细分析实现,就无法给出“为什么”。但最有可能的是,编译器选择的变量布局导致其中一些在读入其他变量时被破坏。

    使用我的编译器,在添加一行打印出a, b, d, e 的地址后,我得到了输出

    0
    70
    0x7fffa94d30ca
    0x7fffa94d30c8
    0x7fffa94d30c6
    0x7fffa94d30c4
    

    所以发生的事情可能是¹

    1. a 的扫描在0x7fffa94d30ca 的低位字节中存储了10,在接下来的三个字节(小端机器)中存储了0,覆盖了两个未分配给任何变量的堆栈字节,不幸的是没有致命的后果,
    2. 扫描到b0x7fffa94d30c8的字节中存储20,在接下来的三个字节中存储0,覆盖分配给a的两个字节,因此将a设置为0,
    3. 扫描到e(巧妙地按照字母和声明顺序完成)在0x7fffa94d30c4的字节中存储了30,在接下来的三个字节中存储了0,其中最后两个是分配d的位置,但是d 之后被扫描到,所以
    4. 扫描到d0x7fffa94d30c6的字节中存储40,在接下来的三个字节中存储0,用0覆盖b
    5. c = a + b 加法结果为 0,因为扫描到其他变量时这两个变量都被覆盖,而f = d + e 加法结果为 70,因为扫描后 de 都没有被覆盖。

    强制c 被分配到堆栈上,而不是通过打印出它的地址来放置在寄存器中导致这里扫描到d 覆盖c 而不是b 并相应地添加@987654344 @ 结果为 20。

    ¹ 由于使用 %d 格式说明符扫描到 short int 变量是未定义的行为,任何事情都可能发生,但如果编译器没有竭尽全力利用 UB,简单的解释将是正确的一个。

    【讨论】:

      【解决方案3】:

      发生的事情是“%d”指示 scanf 从输入中读取和解析一个数字,将其转换为 int,并将该 int 存储在相应的地址。通常,一个 int 是 32 位(四个字节),一个短 int 是 16 位(两个字节),虽然这可能会有所不同。

      虽然 scanf 为每个“%d”写入四个字节,但您只为 &a、&b、&e 和 &d 中的每个传递了两个字节。所以两个字节到正确的地址,另外两个到 &a、&b、&e 和 &d 旁边的任何地方。其中一些彼此相邻并被杂散字节覆盖。

      很明显,这是非常糟糕的代码,永远不应该使用。你不能指望哪些变量会在内存中紧挨着其他变量。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-12-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-15
        • 2012-11-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多