Как инициализация статической переменной реализована компилятором?

Да, вы можете переключить «Просмотр как» из Пакетов в Проект.

Packages

Project

Для расширения папок снимите флажок Компактные пустые средние пакеты

enter image description here

20
задан e.James 22 May 2009 в 15:20
поделиться

5 ответов

В выходных данных компилятора, которые я видел, локальные статические переменные функции инициализируются точно так, как вы себе представляете.

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

Я должен добавить, что если инициализация локальной статики выполняется простой константой, как в вашем примере, компилятору не нужно пройти через эти колебания - он может просто инициализировать переменную в изображении или до main () , как при обычной статической инициализации (потому что ваша программа не заметит разницы).

12
ответ дан 30 November 2019 в 00:48
поделиться

Этот вопрос касался аналогичных вопросов, но безопасность потоков не упоминалась. Как бы то ни было, C ++ 0x сделает статическую инициализацию функции потокобезопасной. завершение инициализации. ")

Еще одна вещь, о которой не упоминалось, это то, что статика функций разрушается в порядке, обратном их построению, поэтому компилятор поддерживает список деструкторов для вызова при завершении работы (это может или не может будет тем же списком, что и atexit).

11
ответ дан 30 November 2019 в 00:48
поделиться

Вы правы во всем, включая инициализированный флаг как общую реализацию. По сути, именно поэтому инициализация статических локальных переменных не является потокобезопасной и почему существует pthread_once.

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

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

2
ответ дан 30 November 2019 в 00:48
поделиться

Я знаю, что он не будет инициализирован до первого вызова функции. Поскольку компилятор не имеет возможности узнать, когда функция будет вызвана в первый раз, как он производит такое поведение? По сути, вводит ли он блок if в тело функции?

Да, верно: и, FWIW, он не обязательно является потокобезопасным (если функция вызывается «впервые» двумя потоками одновременно).

По этой причине вы можете предпочесть определять переменную в глобальной области (хотя, возможно, в классе или пространстве имен или статическом без внешней связи), а не внутри функции, чтобы она инициализировалась перед запуском программы без какого-либо времени выполнения » если ".

1
ответ дан 30 November 2019 в 00:48
поделиться

Другой поворот - во встроенном коде, где код run-before-main () (cinit / что угодно) может копировать предварительно инициализированные данные (как статические, так и нестатические) в оперативную память из const сегмент данных, возможно, находящийся в ПЗУ. Это полезно, когда код может не запускаться из какого-то резервного хранилища (диска), откуда его можно повторно загрузить. Опять же, это не нарушает требований языка, так как это делается до main ().

Незначительное касание: хотя я не видел, чтобы это было сделано много (за пределами Emacs), программа или компилятор могут в основном запускать ваш код в процессе и создавать / инициализировать объекты, а затем замораживать и выгружать процесс. Emacs делает что-то подобное, чтобы загрузить большое количество elisp (т.е. проглотить его), а затем сбросить текущее состояние в качестве рабочего исполняемого файла, чтобы избежать затрат на синтаксический анализ при каждом вызове.

1
ответ дан 30 November 2019 в 00:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: