朋友问我一道题他碰到的笔试题:
sizeof(b)求b所占用的空间,这个是3没有问题。
strlen仅仅根据'/0'的出现判断字符串大小,而不管'/0'是不是出现在数组之内。由于b的末尾没有'/0',所以strlen(b)的值依赖于程序的内存布局。
我记得李先静兄在《系统程序员成长计划》里提到过gcc对临时变量的进栈顺序处理,查了一下:
“gcc不同版本的处理是不一样的,对于老版本的gcc(如gcc3.4),第一个临时变量放在最高的地址,第二个其次,依次顺序分布。而对于新版本的gcc(如gcc4.3),临时变量的位置是反的,即最后一个临时变量在最高的地址,倒数第二个其次,依次顺序分布。”
不管是临时变量在栈中的顺序是递增还是递减,只要是有序的,那么strlen(b)的值就应该是6,我估计这也是出题者在b的前后各放了一个4字节长的数组的原因。
朋友验证之后告诉我,他在gcc4.4.1下输出是7 3,于是我做了下面的实验,验证临时变量在stack中的排列顺序:
Unbuntu + gcc 4.4.1
输出:
bffff448 bffff444 bffff44d bffff440
7 3
从内存布局可以看出,gcc调整了变量的顺序,难道是为了32bit对齐所作的优化?
接着来,多定义了一个char变量:
输出:
bffff448 bffff444 bffff44c bffff440
3 3
果然是把新定义的char变量放到了b的后面,这些不对齐的变量放到了堆栈的高地址(先入栈)。
接着验证:
输出:
bffff44c bffff448 bffff444 bffff440
7 4
b也是32bit对齐后,变成了先定义的在堆栈高地址(先声明先入栈)。
再来:
输出:
bffff448 bffff444 bffff440 bffff43c
7 4
再次加入char 类型变量之后,不是32bit对齐的char放在了堆栈的高地址处。
windows下用 codeblock + mingw(gcc 4.4.4)测试了一下题目的代码:
堆栈里的数据如下:
gcc4.4.4没有优化32bit对齐,先声明先入栈。
结论:
临时变量在栈中的顺序没有强制规定,完全依赖于编译器的实现,不应该对它做任何假设。
题外话:
这些没有标准可查、像期末考试题一样的笔试题不知道什么时候才能消失。