理解堆栈地址操作

时间:2015-12-30 14:02:18

标签: c

  

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

struct mystruct {
  char a;
  int b;
  short c;
  char d;
};
int main()
{
  struct mystruct foo[3];
  char ch;
  int i;

  printf("%p %p %p %p %p\n", &foo[0], &foo[1], &foo[2], &ch, &i);

  return 0;
}
     

以下哪一项最有可能成为其产出的候选人?

     
      
  1. 0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeece8f 0xfeeece88
  2.   
  3. 0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeeceb4 0xfeeeceb8
  4.   
  5. 0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeeceb4 0xfeeeceb5
  6.   
  7. 0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeece8c 0xfeeece88
  8.   

输出是选项(1)。我无法理解,选项a如何是正确的答案..

堆栈从较高地址增长到较低地址。此处foo[3]foo[2]foo[1]foo[0]chi ... i位于较低地址堆栈和foo[3]在更高的地址。此处sizeof(mystruct)为16,因此foo[3]foo[2]foo[1]ch的地址间隔为16。

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

0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeece8f 0xfeeece88

1 个答案:

答案 0 :(得分:4)

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

  • a位于偏移0
  • 3个字节的填充以使b与4个字节对齐
  • b抵消4
  • c偏移8(不需要填充,我们已经是2的倍数)
  • d偏移量为10(无需填充,char不需要任何特定对齐)
  • 填充的1个字节,以保持数组的下一个元素在4个字节边界上(以便所有元素的b保持与4个字节边界对齐)。

因此,在这方面所有选择都是合理的;接下来是ch;假设编译器保持变量的顺序(在优化的构建中肯定合理)将位于foo之上。 foo0xfeeece90开始,ch没有对齐要求,因此它将是0xfeeece8f。最后,i将位于ch上方最近的4字节边界,这确实是0xfeeece88

再次说明:这个讨论对于{em>与struct有关是现实的,在讨论当地人时并不是这样。在优化的构建中,声明的顺序无关紧要,编译器可能会对它们进行重新排序以避免浪费空间(并且,如果您不要求它们的地址,则会尝试将它们放入寄存器中)。