В каком сегменте (.BSS, .DATA и т. Д.) Исполняемого файла хранятся статические переменные, чтобы избежать конфликта имен? Например:
foo.c: bar.c:
static int foo = 1; static int foo = 10;
void fooTest() { void barTest() {
static int bar = 2; static int bar = 20;
foo++; foo++;
bar++; bar++;
printf("%d,%d", foo, bar); printf("%d, %d", foo, bar);
} }
Если я скомпилирую оба файла и свяжу их с основным, который неоднократно вызывает fooTest () и barTest, операторы printf увеличиваются независимо. Имеет смысл, поскольку переменные foo и bar являются локальными для модуля перевода.
Но где выделено хранилище?
Чтобы было ясно, предполагается, что у вас есть набор инструментов, который будет выводить файл в формате ELF. Таким образом, я считаю , что имеет быть некоторое пространство , зарезервированное в исполняемом файле для этих статических переменных.
Для обсуждения давайте предположим, что мы используем набор инструментов GCC.
c++
c
compiler-construction
Benoit
источник
источник
Ответы:
Куда идут ваши статики, зависит от того, инициализированы ли они нулем . Инициализированные нулем статические данные помещаются в .BSS (блок, начатый символом) , ненулевые инициализированные данные помещаются в .DATA
источник
.data
, и статические данные без инициализатора.bss
.Когда программа загружается в память, она организуется в разные сегменты. Одним из сегментов является сегмент DATA . Сегмент данных далее подразделяется на две части:
Сегмент инициализированных данных: здесь хранятся все глобальные, статические и постоянные данные.
Сегмент неинициализированных данных (BSS): все неинициализированные данные хранятся в этом сегменте.
Вот схема, чтобы объяснить эту концепцию:
Вот очень хорошая ссылка, объясняющая эти понятия:
источник
Фактически, переменная является кортежем (хранилище, область действия, тип, адрес, значение):
Локальная область действия может означать локальную либо для единицы перевода (исходного файла), функции или блока в зависимости от того, где она определена. Чтобы сделать переменную видимой для более чем одной функции, она определенно должна находиться в области DATA или BSS (в зависимости от того, инициализирована она явно или нет, соответственно). Затем его масштабируют соответственно всем функциям или функциям в исходном файле.
источник
Место хранения данных будет зависеть от реализации.
Однако значение статического - это «внутренняя связь». Таким образом, символ является внутренним для модуля компиляции (foo.c, bar.c) и на него нельзя ссылаться вне этого модуля компиляции. Таким образом, не может быть никаких конфликтов имен.
источник
в "глобальной и статичной" области :)
В C ++ есть несколько областей памяти:
Смотрите здесь для подробного ответа на ваш вопрос:
источник
Я не верю, что будет столкновение. Использование статического на уровне файла (внешние функции) помечает переменную как локальную по отношению к текущему модулю компиляции (файлу). Он никогда не виден за пределами текущего файла, поэтому никогда не должен иметь имя, которое можно использовать извне.
Использование статического внутри функции отличается - переменная видна только функции (статической или нет), просто ее значение сохраняется при вызовах этой функции.
По сути, static делает две разные вещи в зависимости от того, где он находится. Однако в обоих случаях видимость переменной ограничена таким образом, что вы можете легко предотвратить столкновения пространства имен при связывании.
Сказав это, я полагаю, что он будет храниться в
DATA
разделе, который имеет переменные, которые инициализируются значениями, отличными от нуля. Это, конечно, деталь реализации, а не то, что предписано стандартом - она заботится только о поведении, а не о том , как все делается под прикрытием.источник
So, how does a segment of memory (Data Segment) store variables that can be accessed from everywhere (global variables) and also those which have limited scope (file scope or function scope in case of static variables)?
Как найти это самостоятельно
objdump -Sr
Чтобы действительно понять, что происходит, вы должны понимать перемещение компоновщика. Если вы никогда не касались этого, сначала прочитайте этот пост .
Давайте проанализируем пример Linux x86-64 ELF, чтобы увидеть его сами:
Компилировать с:
Декомпилируйте код с помощью:
-S
декомпилирует код с исходным кодом-r
показывает информацию о переездеВнутри декомпиляции
f
мы видим:и
.data-0x4
говорит, что он пойдет в первый байт.data
сегмента.Это
-0x4
происходит потому, что мы используем относительную адресацию RIP, то есть%rip
в инструкции иR_X86_64_PC32
.Это необходимо, потому что RIP указывает на следующую инструкцию, которая начинается через 4 байта, после
00 00 00 00
чего происходит перемещение. Я объяснил это более подробно по адресу: https://stackoverflow.com/a/30515926/895245Затем, если мы изменим источник
i = 1
и проведем тот же анализ, мы заключим, что:static int i = 0
продолжается.bss
static int i = 1
продолжается.data
источник
Вот как (легко понять):
источник
Это зависит от платформы и компилятора, который вы используете. Некоторые компиляторы хранят прямо в сегменте кода. Статические переменные всегда доступны только для текущей единицы перевода, а имена не экспортируются, поэтому никогда не возникает конфликт имен.
источник
Данные, объявленные в модуле компиляции, попадут в файлы .BSS или .Data этих файлов. Инициализированные данные в BSS, неинициализированные в DATA.
Разница между статическими и глобальными данными заключается во включении символьной информации в файл. Компиляторы, как правило, включают информацию о символах, но отмечают только глобальную информацию как таковую.
Компоновщик уважает эту информацию. Информация о символах для статических переменных либо отбрасывается, либо искажается, так что на статические переменные все же можно каким-то образом ссылаться (с помощью параметров отладки или символов). Ни в том, ни в другом случае блоки компиляции не могут быть затронуты, так как компоновщик сначала разрешает локальные ссылки.
источник
Я попробовал это с objdump и gdb, вот результат, который я получаю:
вот результат objdump
Итак, ваши четыре переменные находятся в разделе данных под одним и тем же именем, но с разным смещением.
источник
статическая переменная хранится в сегменте данных или сегменте кода, как упоминалось ранее.
Вы можете быть уверены, что он не будет размещен ни в стеке, ни в куче.
Нет риска для столкновения, так как
static
ключевое слово определяет область действия переменной как файла или функции, в случае столкновения есть компилятор / компоновщик, чтобы предупредить вас.Хороший пример
источник
Ну, этот вопрос немного устарел, но поскольку никто не указывает на какую-либо полезную информацию: проверьте сообщение от 'mohit12379', объясняющее хранилище статических переменных с тем же именем в таблице символов: http://www.geekinterview.com/question_details/ 24745
источник
Ответ вполне может зависеть от компилятора, поэтому вы, вероятно, захотите отредактировать свой вопрос (я имею в виду, что даже понятие сегментов не является обязательным ни в ISO C, ни в ISO C ++). Например, в Windows исполняемый файл не содержит имен символов. Один 'foo' будет смещен на 0x100, другой, возможно, на 0x2B0, и код из обоих модулей перевода будет скомпилирован с учетом смещений для "их" foo.
источник
они оба будут храниться независимо, однако, если вы хотите прояснить это другим разработчикам, вы можете заключить их в пространства имен.
источник
вы уже знаете, хранится ли он в bss (начало блока по символу), также называемом сегментом неинициализированных данных, или в сегменте инициализированных данных.
давайте возьмем простой пример
вышеуказанная статическая переменная не инициализируется, поэтому она переходит в неинициализированный сегмент данных (bss).
и, конечно, он инициализируется 10, поэтому он переходит в инициализированный сегмент данных.
источник