Краткое объяснение состоит в том, что если вы объявили «x» в строке исходного кода после «buf», это не означает, что компилятор поместил их рядом друг с другом в стеке. С указанным кодом 'x' вообще не используется, поэтому, вероятно, он не был помещен в любом месте . Даже если вы как-то использовали 'x' (и это должно было бы быть способом, предотвращающим его вставку в регистр), есть большая вероятность, что компилятор отсортирует его ниже 'buf' именно так, чтобы не перезаписывается кодом, переполняющим 'buf'.
Вы можете заставить эту программу перезаписывать 'x' конструкцией struct
, например,
#include <stdio.h>
int main()
{
struct {
char buf[5];
char x[2];
} S = { { 0 }, { 'u' } };
printf("Please enter your name: ");
gets(S.buf);
printf("Hello %s!\n", S.buf);
printf("S.x[0] = %02x\n", S.x[0]);
return 0;
}
, поскольку поля struct
всегда располагаются в памяти в порядке их появления в исходном коде. 1 В принципе между S.buf
может быть заполнение и S.x
, но char
должно иметь требование выравнивания 1, поэтому, вероятно, ABI этого не требует.
Но даже если вы сделаете , что , оно не выведет «Hello stacku!», Потому что gets
всегда записывает завершающий NUL. Смотреть:
$ ./a.out
Please enter your name: stac
Hello stac!
S.x[0] = 75
$ ./a.out
Please enter your name: stack
Hello stack!
S.x[0] = 00
$ ./a.out
Please enter your name: stacks
Hello stacks!
S.x[0] = 73
Посмотрите, как она всегда печатает набранный вами текст, но x[0]
перезаписывается, сначала с NUL, а затем с '?' *
(Вы уже читали Разбить стек ради удовольствия и прибыли ? Вам следует.)
1 Сноска для педантов: если задействованы битовые поля, порядок полей в памяти частично определяется реализацией. Но это не важно для целей этого вопроса.