Скажем, что у меня есть программа на C, и она имеет следующую строку:
int a = 12;
Является ли значение 12 привязано к 'a' во время компиляции? Или значение, помещенное в память во время выполнения, когда область действия программы достигает "a"?
Как насчет языков программирования, таких как Python и Ruby?
Существуют ли языки/экземпляры, где значение статически привязано к переменной? Я уже давно об этом думаю, и я честно не могу думать о логической причине статической привязки значения к примитивному типу.
Значение 12 не статически привязано к a
. Скорее, a
привязан к ячейке памяти, которая инициализируется значением 12.
Если a
были объявлены как const
, и ничто никогда не принимало его адрес, компилятору не нужно было бы выделять хранилище и использовать его как константу времени компиляции, и в этом случае значение 12 было бы статически связанный с a
.
Компиляторы и виртуальные машины эффективно "реализуют" языки программирования. Они должны делать только то, что определено семантикой языка и наблюдаемое для данной программы, чтобы быть верным.
Когда вы пишете оператор определения int a = 12;
в программе на C, вы сообщаете компилятору, что есть переменная с именем a
, для которой начальное значение установлено на постоянный литерал двенадцать.
Если вы никогда не наблюдаете a
, компилятор может полностью избавиться от него, потому что вы не можете определить разницу во время выполнения программы по спецификации языка. (Например, если вы должны были приостановить программу и проверить стек в этой точке, значение 12 вообще не должно быть там. Его необходимость находиться в стеке машины не является частью спецификации языка.)
Если вы наблюдаете a
, но обнаружите, что ваша программа не может изменить его значение, компилятор предположил, что он на самом деле static const
и может выполнять оптимизацию, называемую "постоянным распространением", чтобы нажимать жестко закодированные двенадцать в зависимые инструкции.
Если вы сделаете ссылку на a
, a la int *aptr = &a;
, тогда спецификация языка говорит, что a
должно иметь место в памяти (IIRC). Это означает, что в соответствии с спецификацией в памяти будет установлен допустимый интервал размера в размере (в стеке, в любой разумной реализации), который будет содержать 12.
В других языках есть, очевидно, другие спецификации. Технически, в динамических языках компилятор может выполнять аналогичные оптимизации. Если у вас есть функция Python:
def do_nothing():
a = 12
Можно предположить, что компилятор Python, который превращает текст языка в байт-коды, может полностью исключить тело этой функции (для педантов: кроме неявного return None
). Традиционно реализации Python не имеют такой оптимизации, поскольку ее философия языка требует отладки, простоты реализации VM и понимания программистов выше оптимизаций.
Существуют также некоторые сложные конструкции в динамических языках, которые затрудняют вывод. Например, Python позволяет проводить большую проверку объектов кода, которая, как ожидается, будет работать во всех реализациях. Приобретение/проверка трассировки стека и локальные аргументы активированных кадров требуют, по крайней мере, механизмов замедления медленного пути, что значительно увеличивает сложность оптимизации. Мы отказываемся от поддержки некоторых из этих типов событий проверки на уровне языка-времени выполнения в JavaScript с версией ECMAScript 5.
Поддержка отладчиков сложна, отпустите оптимизацию!
Это зависит от контекста использования переменных и оптимизаций компилятора, которые вы включили. Если переменная никогда не обновляется и не используется в достаточно малой области, ее, скорее всего, скомпилируют в конечном выпуске, даже в самых легких вариантах оптимизации. Если компилятор обнаруживает, что переменная передается или обновляется позже (или потенциально обновляется позже), она может загружать целое число в стек. Это зависит от архитектуры, но если она обновляется только через некоторое время, а затем удаляется, она может загружать ее в регистр, если это возможно, и работать с ней там.
В CPython он может делать подобные оптимизации в некоторых случаях, если он может обладать переменной (если только ее глобальная, то она будет загружена в кучу). В обычном Ruby он может делать что-то подобное. В Jython и JRuby они определенно оптимизируют то же самое, что и процесс JIT.
Я не полный эксперт, так как я только написал очень простые компиляторы, которые выводят на байт-код, чтобы быть JITed позже, и это было много лет назад.
Я думаю, что a
не может быть статически привязана, потому что a
не является константой, а это значит, что одновременно может быть более одного значения a
(например, объявление a
в рекурсивной функции), Важно, чтобы каждое значение a
должно иметь отдельный адрес в памяти, что подразумевает, что a
не может быть статически привязано к определенному одному адресу памяти.
&a
?