C 理解堆栈地址操作

C 理解堆栈地址操作,c,C,考虑以下代码(在32位Intel/Linux系统上): 以下哪项最有可能成为其输出的候选项 0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeece8f 0xfeeece88 0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeeceb4 0xfeeeceb8 0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeeceb4 0xfeeeceb5 0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeee

考虑以下代码(在32位Intel/Linux系统上):

以下哪项最有可能成为其输出的候选项

  • 0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeece8f 0xfeeece88
  • 0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeeceb4 0xfeeeceb8
  • 0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeeceb4 0xfeeeceb5
  • 0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeece8c 0xfeeece88
  • 输出为选项(1)。我不明白,a选项怎么是正确答案

    堆栈从较高的地址增长到较低的地址。这里是
    foo[3]
    foo[2]
    foo[1]
    foo[0]
    ch
    i
    i
    将位于堆栈的较低地址,而
    foo[3]
    位于较高地址。这里的
    sizeof(mystruct)
    是16,因此
    foo[3]
    foo[2]
    foo[1]
    ch
    的地址间隔将是16

    我无法通过以下地址获得地址差异16:

    0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeece8f 0xfeeece88
    

    提供给您的选项假设一个12字节的
    sizeof(mystruct)
    ,这是合理的,因为

    • 偏移量0处的
      a
    • 3个字节的填充,使
      b
      与4个字节对齐
    • 偏移量4处的
      b
    • 偏移量8处的
      c
      (无需填充,我们已经处于2的倍数)
    • 偏移量10处的
      d
      (无需填充,
      char
      不需要任何特定对齐)
    • 1字节的填充,将数组的下一个元素保留在4字节边界上(以便所有元素的
      b
      保持与4字节边界对齐)
    因此,在这方面,所有的选择都是合理的;接下来是
    ch
    ;假设编译器保持了变量的顺序(这在优化的构建中肯定是不合理的),那么它将位于
    foo
    之上
    foo
    0xfeeece90
    开始,并且
    ch
    没有对齐要求,因此它将是
    0xfeeece8f
    。最后,
    i
    将位于
    ch
    上方最近的4字节边界处,这实际上是
    0xfeeece88


    再次强调:就结构而言,这种讨论是现实的,而不是在讨论局部变量时。在优化的构建中,声明的顺序无关紧要,编译器可能会对它们重新排序以避免浪费空间(如果您不要求它们的地址,则会尝试将它们放入寄存器中)。

    您只需记住堆栈的增长方向,以及问题中各种积分类型之间的相对
    sizeof
    关系。以及由于对齐而导致的结构填充。这里的
    sizeof(mystruct)
    是16-您检查了吗?使用
    printf(“%p”
    是少数几个实际应该将指针强制转换为
    void*
    的情况之一。
    int*
    struct mystruct*
    的表示形式可能不同于
    void*
    的表示形式。未能强制转换可能会触发UB为什么它不能成为最后一个选项
    0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeece8c 0xfeeece88
    @Angus:因为
    c
    是一个字符,不需要与4个字节的边界对齐。@Angus:对不起,我在答案的最后部分弄错了一些名称(在上一条评论中我指的是
    ch
    ),现在检查一下它是否更有意义。
    0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeece8f 0xfeeece88