Intereting Posts
Виртуальное адресное пространство в контексте программирования как вы меняете две строки в матрице (в C)? Преобразование long long int в строку без sprintf с использованием функций Преобразование двухзначного числа в слова с использованием оператора switch Замена пробелов на% 20 в C Прототип функции объявлен внутри основного – лучшая практика? Как сообщить openmp не синхронизировать массив Когда использовать массив переменной длины в C, но когда динамическое распределение? предупреждение: ошибка неявного объявления Включение и тестирование локального цикла для UART Советы по обертке библиотеки C в Objective-C спецификатор формата printf в аргументе сборки SPARC? C: создание массива строк из строки источника с разделителями Правильный способ записи и чтения строки с нулевым завершением с памятью OpenSSL BIO Работа с std :: function в библиотеках C

Что действительно делает компилятор, когда мы объявляем статические переменные?

Я хочу знать, что на самом деле происходит под капотом, как компилятор рассматривает статические переменные. В отличие от автоматической переменной значение статической переменной сохраняется даже после окончания блока, но как компиляторы действительно справляются с этим?

В отличие от локальных переменных, которые идут на стек, статические переменные хранятся в специальных сегментах данных. Какой сегмент занимает ваша статическая переменная, зависит от того, были ли они инициализированы или нет. 0 инициализированных статических данных поступает в .BSS (Block Started by Symbol), но не инициализированные данные идут в .DATA .

Если вы хотите узнать больше о разных сегментах в исполняемых файлах, эта статья в Википедии является хорошей отправной точкой. Я также настоятельно рекомендую Глава 7 в компьютерных системах: «Перспектива программиста» Рэндала Э. Брайанта и Дэвида Р. О’Халларона.

Я описываю здесь один конкретный сценарий. Вы должны учитывать, что детали будут варьироваться от одной архитектуры к другой, от одной ОС до другой и т. Д. И т. Д. Однако общий макет исполняемых файлов остается таким, как описано. Удивительно!

РЕДАКТИРОВАТЬ:

Автор любезно попросил меня уточнить:

какова точка деления инициализированной переменной 0 на .bss и non 0, инициализированной на .data?

Из раздела 7.4 в компьютерных системах: перспектива программиста в секции .BSS :

Этот раздел не занимает фактического места в объектном файле; это просто место. Форматы файлов объектов различают инициализированные и неинициализированные переменные для эффективности пространства: неинициализированные переменные не должны занимать какое-либо фактическое дисковое пространство в объектном файле.

И, из Википедии :

Обычно в объектный файл хранится только длина секции .BSS , но нет данных. Программный загрузчик выделяет и инициализирует память для секции bss при загрузке программы.

Подводя итог: это механизм экономии памяти.

Типичные компиляторы C производят сборку, которая создает четыре «секции» памяти. Компилятор / загрузчик обычно объединяет различные элементы, помеченные тем же самым разделом, вместе с загрузкой программы в память. Наиболее распространенные разделы:

«текст»: это фактический программный код. Он считается доступным только для чтения (например, компоновщик / загрузчик на некоторых машинах может разместить его в ПЗУ).

«data»: это просто выделенная область ОЗУ с исходными значениями, скопированными из исполняемого файла. Загрузчик выделит память, а затем скопирует ее в исходное содержимое.

«bss»: То же, что и данные, но инициализируется нулями.

«stack»: просто выделяется загрузчиком для его стека программ.

Глобальные и статические переменные помещаются в «данные» и «bss» и поэтому имеют срок службы программы. Однако статические переменные не помещают свои имена в таблицу символов, поэтому они не могут быть связаны извне как глобальные. Видимость и время жизни переменных – это совершенно разные понятия: синтаксис C смущает два.

«Автоматические» переменные обычно выделяются в стеке во время выполнения программы (хотя, если они очень большие, они могут быть выделены вместо кучи). Они существуют только в рамке стека.

static переменные – это глобальные переменные с ограниченной областью. @ user3386109

  1. static / глобальные переменные для времени жизни программы.
  2. static / global инициализируются при запуске программы:

    A. Если явно не инициализируется: к шаблону бит 0 .
    B. В противном случае к явному значению, например double x = 1.23;

  3. область видимости переменных переменных ограничена

    A. Если определено вне функции: область файла, только код внутри файла может «видеть» переменную.
    B. Если определено внутри функции: область блока: только код внутри блока может «видеть» переменную.

  4. В своей области есть только один экземпляр static переменной, если нижняя область не определяет другую с тем же именем. Компилятор «знает», с той же самой именованной переменной для доступа, сначала используя ближайшую область. Он не воссоздается и не инициализируется, даже если внутри функции.

Примечание. При использовании нескольких streamов применяются другие соображения – не показаны.

 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++; } 

Другими словами, это своего рода «глобальная» переменная, имя которой, однако, не конфликтует с какой-либо другой глобальной переменной.