Посмотрите на эти две функции:
void function1() {
int x;
int y;
int z;
int *ret;
}
void function2() {
char buffer1[4];
char buffer2[4];
char buffer3[4];
int *ret;
}
Если я разбью на function1()
в gdb
и выведу адреса переменных, я получу это:
(gdb) p &x
$1 = (int *) 0xbffff380
(gdb) p &y
$2 = (int *) 0xbffff384
(gdb) p &z
$3 = (int *) 0xbffff388
(gdb) p &ret
$4 = (int **) 0xbffff38c
Если я делаю то же самое в function2()
, я получаю это:
(gdb) p &buffer1
$1 = (char (*)[4]) 0xbffff388
(gdb) p &buffer2
$2 = (char (*)[4]) 0xbffff384
(gdb) p &buffer3
$3 = (char (*)[4]) 0xbffff380
(gdb) p &ret
$4 = (int **) 0xbffff38c
Вы заметите, что в обеих функциях ret
хранится ближе всего к вершине стека. В function1()
за ним следуют z
, y
и, наконец, x
. В function2()
, ret
сопровождается buffer1
, затем buffer2
и buffer3
. Почему изменился порядок хранения? Мы используем одинаковый объем памяти в обоих случаях (4 байта int
с против 4 байтов char
массивов), поэтому это не может быть проблемой заполнения. Какие могут быть причины для такого переупорядочения, и, кроме того, возможно ли, взглянув на код C, заранее определить, как будут упорядочены локальные переменные?
Теперь я знаю, что спецификация ANSI для C ничего не говорит о порядке, в котором хранятся локальные переменные, и что компилятору разрешено выбирать свой собственный порядок, но я думаю, что у компилятора есть правила относительно того, как позаботится об этом и объяснит, почему эти правила были сделаны такими, какие они есть.
Для справки я использую GCC 4.0.1 в Mac OS 10.5.7