Что на самом деле делает компилятор, когда мы объявляем статические переменные?
Я хочу знать, что на самом деле происходит под капотом,как компилятор обрабатывает статические переменные. В отличие от автоматической переменной, значение статической переменной сохраняется даже после окончания блока, но как компиляторы фактически справляются с этим?
4 ответов
В отличие от локальных переменных, которые идут в стек, статические переменные хранятся в специальных сегментах данных. В какой сегмент переходит статическая переменная, зависит от того, инициализированы они 0 или нет. 0 инициализированные статические данные входят в .BSS (блок запускается символом), не 0 инициализированные данные входят в .Данные.
Если вы хотите узнать больше о различных сегментах в исполняемых файлах,этой Wikipedia запись является хорошей отправной точкой. Я тоже настоятельно рекомендую Главу 7 в компьютерные системы: взгляд программиста Рэндал Э. Брайант и Дэвид Р. О'Халларон.
я описываю здесь один конкретный сценарий. Нужно учитывать, что детали могут варьироваться от одной архитектуры к другой, от одной ОС к другой, и так далее. Однако общая компоновка исполняемых файлов остается описанной. Действительно, захватывающая штука!
изменить:
автор любезно попросил меня уточнить:
какова точка деления инициализированной переменной 0 на .bss и не 0 инициализировано .Дейта?
из раздела 7.4 в компьютерные системы: взгляд программиста на .BSS:
этот раздел не занимает фактического пространства в объектном файле; это просто заполнитель. Форматы объектных файлов различают инициализированные и неинициализированные переменные для эффективность космоса: неинициализированный переменные не должны занимать какое-либо фактическое дисковое пространство в объекте файл.
и Википедия:
обычно только длина .BSS раздел, но нет данных, сохраняется в объектном файле. Загрузчик программ выделяет и инициализирует память для раздела bss при загрузке программы.
подведем итог: это механизм для сохранения памяти.
типичные компиляторы C производят вывод сборки, который создает четыре "секции" памяти. Компоновщик / загрузчик обычно объединяет различные элементы, помеченные одним и тем же разделом, при загрузке программы в память. Наиболее распространенными разделами являются:
"текст": это фактический программный код. Он считается доступным только для чтения (например, компоновщик/загрузчик на некоторых машинах может поместить его в ПЗУ).
"данные": это просто выделенная область ОЗУ, с копированными начальными значениями из исполняемого файла. Загрузчик выделит память, а затем скопирует ее исходное содержимое.
"bss": то же, что и данные, но инициализируется нулями.
"stack": просто выделяется загрузчиком для своего стека программы.
глобальные и статические переменные помещаются в "данные" и "bss" и, следовательно, имеют срок службы программы. Однако статические переменные не помещают свои имена в таблицу символов, поэтому они не могут быть связаны извне, как глобалы. Видимость и время жизни переменных-совершенно разные понятия: синтаксис C путает их.
переменные"Auto" обычно выделяются в стеке во время выполнения программы (хотя, если они очень большие, они могут быть выделены в куче). Они существуют только в рамках своего стека.
static
переменные-это глобальные переменные с ограниченной областью действия. @user3386109
-
static
/ глобальные переменные существуют в течение всего срока службы программы. -
static
/ global инициализируются при запуске программы либо:A. Если явно не инициализировать: к битовому шаблону
0
.
B. В противном случае к явному значению, такому какdouble x = 1.23;
-
static
объем переменных либо ограниченоA. Если определено вне функции: область файла, только код в файле может "видеть" переменную.
B. Если определено внутри функции: область блока: только код внутри блока может "видеть" переменную. существует только один экземпляр
static
переменная в пределах своей области, если нижняя область не определяет другую с тем же именем. Компилятор "знает", какая же именованная переменная для доступа, используя ближайшую область. Это не re-created или re-initialized, даже если внутри функции.
Примечание: с несколькими потоками, другие соображения - не показано.
static int fred = 11;
int sally = 21;
void foo2(void) {
static int fred = 31;
int sally = 41;
printf("static %d non-static %d\n", fred++, sally++);
{
printf("static %d non-static %d\n", fred++, sally++);
{
static int fred = 51;
int sally = 61;
printf("static %d non-static %d\n", fred++, sally++);
}
}
}
int main(void) {
printf("static %d non-static %d\n", fred++, sally++);
foo2();
printf("static %d non-static %d\n", fred++, sally++);
foo2();
return 0;
}
выход
static 11 non-static 21
static 31 non-static 41
static 32 non-static 42
static 51 non-static 61
static 12 non-static 22
static 33 non-static 41
static 34 non-static 42
static 52 non-static 61
этот код:
void function()
{
static int var = 6;
// Make something with this variable
var++;
}
внутренне похоже на это:
int only_the_compiler_knows_this_actual_name = 6;
void function()
{
// Make something with the variable
only_the_compiler_knows_this_actual_name++;
}
другими словами, это своего рода" глобальная " переменная, имя которой, однако, не конфликтует ни с какой другой глобальной переменной.