C 理解堆栈地址操作
考虑以下代码(在32位Intel/Linux系统上): 以下哪项最有可能成为其输出的候选项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
0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeece8f 0xfeeece88
0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeeceb4 0xfeeeceb8
0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeeceb4 0xfeeeceb5
0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeece8c 0xfeeece88
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个字节的填充,使
与4个字节对齐b
- 偏移量4处的
b
- 偏移量8处的
(无需填充,我们已经处于2的倍数)c
- 偏移量10处的
(无需填充,d
不需要任何特定对齐)char
- 1字节的填充,将数组的下一个元素保留在4字节边界上(以便所有元素的
保持与4字节边界对齐)b
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