Я не вижу здесь ничего плохого. Ответ TLDR: массивы символов выровнены по 1 байту , компилятор прав.
Копаем немного дальше. На моей 64-битной машине, используя G CC 7 с опцией -m32, я запускаю и отлаживаю один и тот же код и получаю одинаковые результаты:
(gdb) x/4bd $esp+12
0xffffcdd4: 97 97 97 97
(gdb) x/4bd $esp+8
0xffffcdd0: 0 -48 -7 97
(gdb) x/4bd $esp+4
0xffffcdcc: 0 0 0 0
(gdb) x/4bd $esp+0
0xffffcdc8: 41 85 85 98
Конечно, адреса разные, и это хорошо. Теперь позвольте мне попытаться объяснить. Во-первых, $esp
выровнен по 4 байта, как и ожидалось:
(gdb) p $esp
$9 = (void *) 0xffffcdc8
Пока все хорошо. Теперь, поскольку мы знаем, что в массивах char по умолчанию используется 1 , давайте попробуем выяснить, что произошло во время компиляции. Сначала компилятор увидел array1[5]
и поместил его в стек, но, поскольку он имел ширину 5 байт, он расширил его до второго слова. Итак, первый меч полон 'a', в то время как использовался только 1 байт второго меча. Теперь array2[8]
помещается сразу после (или раньше, в зависимости от того, как вы выглядите) array1[5]
. Он распространяется на 3 слова и заканчивается словом, обозначенным $esp
.
Итак, у нас есть:
[esp + 0] <3 bytes of garbage /* no var */>, 'b' /* array2 */,
[esp + 4] 0x0, 0x0, 0x0, 0x0, /* still array2 */
[esp + 8] <3 bytes of garbage /* still array2 */>, 'a' /* array1 */,
[esp + 12] 'a', 'a', 'a', 'a', /* still array1 */.
Если вы добавите массив char[2]
после array2
you ' Вы увидите его, используя то же двойное слово, на которое указывает $esp
, и все равно у вас будет 1 байт мусора от $esp
до вашего array3[2]
.
Компилятору абсолютно разрешено это делать. Если вы хотите, чтобы ваши char
массивы были выровнены по 4 байта (но вам нужна хорошая причина для этого!), Вы должны использовать специальные атрибуты компилятора, такие как:
__attribute__ ((aligned(4)))