Что в Си находится в переменной до присваивания значения человеком?
Вот у меня есть код
#include <stdio.h>
void what_in_variable1(void);
void what_in_variable2(void);
void what_in_variable3(void);
int main(void)
{
what_in_variable1();
what_in_variable2();
what_in_variable3();
return 0;
}
void what_in_variable1(void)
{
int a;
int b;
int c;
printf("a znachenie %d\n", a);
printf("b znachenie %d\n", b);
printf("c znachenie %d\n", c);
}
void what_in_variable2(void)
{
int d;
int e;
int f;
printf("d znachenie %d\n", d);
printf("e znachenie %d\n", e);
printf("f znachenie %d\n", f);
}
void what_in_variable3(void)
{
int q;
int o;
int p;
printf("q znachenie %d\n", q);
printf("o znachenie %d\n", o);
printf("p znachenie %d\n", p);
}
Код возвращает сообщения
a znachenie 0
b znachenie -134327328
c znachenie 32767
d znachenie 0
e znachenie -134327328
f znachenie 32767
q znachenie 0
o znachenie -134327328
p znachenie 32767
Очевидно это не те данные которые были в памяти до того как её выделили под переменную, иначе все цифры были бы разными. По той же причине это не могут быть адреса ячеек памяти которые выделяются под переменные. При этом последняя объявленная в функции переменная всегда равна 32767
, объявленная перед ней всегда равна -134327328
, а ещё одна перед ней всегда равна 0
. То есть если бы объявил только a
и b
то уже a
была бы -134327328
а b
была бы 32767
.
Или код компилируется так что переменным до присваивания значений человеком всегда присваиваются какие-то дефолтные значения в зависимости от того в каком порядке объявлена переменная?
И если это так то можно ли как-то сделать такой код который не будет присваивать дефолтные значения переменным до присваивания значений человеком а сможет посмотреть что там было изначально? Может быть с этой ячейкой памяти раньше работала другая программа и она оставила там какие-нибудь интересные данные - куки, пароли и т.д.
Ответы (1 шт):
Коротко
Стандартный C: ничего нельзя сказать, неопределённое поведение.
Компилятор GCC: в переменные попадает мусор со стека, во всех трёх функциях один и тот же.
Другой компилятор может сказать что-то другое.
Операционная система иногда заботится о том чтобы одна программа не получала данные другой. Если вы работаете с чувствительными данными, их надо затирать после использования.
Длинно
Вы нарушаете правила языка C: нельзя читать переменную до присвоения ей какого-нибудь значения. Это неопределённое поведение, то есть программа может делать что угодно. Больше язык C ничего не обещает.
Но конкретный компилятор с конкретными настройками может делать что-то конкретное. Посмотрим что сделает GCC с вашим кодом:
$ gcc -S temp.c $ cat temp.s
В temp.s
лежит ассемблер программы.
main
вызывает функции подряд:
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
call what_in_variable1
call what_in_variable2
call what_in_variable3
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
Сравним две функции. У них почти одинаковый код, кроме ссылок на строки для печати. Нас интересуют инструкции
movl -12(%rbp), %eax
,
movl -8(%rbp), %eax
,
movl -4(%rbp), %eax
.
Они копируют переменные со стека в регистр eax
. rbp
- указывает на вершину стека, смещения -12
, -8
, -4
ссылаются на разные места в стеке. Расстояние между смещениями ровно четыре байта, это размер целой переменной.
Обе функции читают байты из одного и того же места на стеке. Поэтому они читают одни и теже случайные значения:
what_in_variable1 |
what_in_variable2 |
---|---|
|
|