Эффективность объявления переменной C [дубликат]

7
задан Michael Dickens 24 December 2009 в 02:20
поделиться

12 ответов

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

Более важно правильно выразить намерения вашего кода. Если вам нужна переменная за пределами цикла, обдумайте ее за пределами. Если переменная нужна только внутри цикла, объявите ее внутри.

Вы всегда должны объявлять и инициализировать переменные в как можно более узкой области видимости.

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

.
9
ответ дан 6 December 2019 в 04:49
поделиться

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

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

.
11
ответ дан 6 December 2019 в 04:49
поделиться

Один совет: перестаньте беспокоиться о том, какие языковые конструкции микроскопически быстрее или медленнее, чем другие, и вместо этого сосредоточьтесь на том, какие из них позволяют лучше выразить себя.

Также, чтобы узнать, на что тратится время вашего кода, воспользуйтесь профайлером.

И, как отмечают другие, декларации - это чисто вещи, связанные с временем компиляции, они не влияют на время исполнения.

14
ответ дан 6 December 2019 в 04:49
поделиться

Это совсем не занимает времени. Память для глобальных переменных выделяется при старте, а "объявление" переменных на стеке просто включает в себя то, насколько "вверх" движется указатель стека при вызове функции

.
5
ответ дан 6 December 2019 в 04:49
поделиться

Декларация не занимает никакого времени.

Компилятор будет интерпретировать эту строку как уведомление о том, что в стеке должно существовать место для нее.

.
3
ответ дан 6 December 2019 в 04:49
поделиться

декларации - это чисто время компиляции, они ничего не стоят во время исполнения¹. Но первый кусок кода все равно лучше второго по двум причинам

  • всегда следует инициализировать переменные при их объявлении, так как они никогда не могут иметь неинициализированных значений. Это идет рука об руку с
  • всегда использовать как можно более узкий диапазон объявлений переменных

Так что ваш первый пример, хотя и не быстрее второго, все равно лучше.

И все те, кто скандировали ему, что не надо преждевременно или микро-оптимизировать его код, ошибаются. Никогда не бывает плохо , когда знаешь, как дорого стоят различные биты кода. Самые лучшие программисты хорошо, почти неосознанно, понимают стоимость различных стратегий и автоматически учитывают это при проектировании. Становясь таким программистом, задаешь именно такой вопрос, когда являешься новичком.

¹ На самом деле есть небольшая стоимость, когда каждая функция выделяет место для локальных переменных, но эта стоимость одинакова вне зависимости от того, сколько локальных переменных существует*.

*ок, это не совсем так, но стоимость зависит только от общего количества места, а не от количества переменных.

.
4
ответ дан 6 December 2019 в 04:49
поделиться

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

.
1
ответ дан 6 December 2019 в 04:49
поделиться

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

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

.
1
ответ дан 6 December 2019 в 04:49
поделиться

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

.
1
ответ дан 6 December 2019 в 04:49
поделиться

Отказ от ответственности: именно то, что произойдет, зависит от вашего компилятора, архитектуры и т.д. Но концептуально вот что происходит:

Когда вы объявляете переменную внутри метода, она выделяется на стеке. Выделение чего-то на стеке подразумевает только подкачку указателя стека по размеру переменной. Так, например, если SP представляет адрес памяти верхней части стека, то объявление char x приводит к тому, что SP += 1 и int x приводит к тому, что SP += 4 (на 32-битной машине).

Когда функция выходит из стека, указатель стека возвращается туда, где он был до вызова вашего метода. Так что развязывать все тоже быстро.

Так или иначе, это просто сложение, которое занимает одинаковое количество времени вне зависимости от количества данных.

Умный компилятор объединит несколько объявлений переменных в одно сложение.

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

(Заметное исключение - это C++, который делает дополнительную работу, так как ему нужно вызывать конструкторы и деструкторы, когда создается или уничтожается объект, выделенный из стека.)

.
1
ответ дан 6 December 2019 в 04:49
поделиться

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

1
ответ дан 6 December 2019 в 04:49
поделиться

Переменное объявление компилятором превращается в резервирование стекового пространства. Теперь, как это работает, полностью зависит от платформы. На x86 и практически на всех популярных архитектурах это просто вычитание из адреса кадра стека and\or режима адресации индексации для доступа сверху стека. Все это стоит простого subtraction\addition, что на самом деле не имеет значения.

Технически второй пример менее эффективен, так как объявление происходит при каждом входе в область видимости цикла, т.е. при каждой итерации цикла. Однако вероятность того, что пространство стека будет зарезервировано только один раз, составляет 99.99%. Даже операция присваивания будет оптимизирована, хотя технически она должна выполняться в каждой итерации цикла. Теперь в Си++ это может быть гораздо хуже, если переменная имеет конструктор, который будет выполняться на каждой итерации цикла.

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

0
ответ дан 6 December 2019 в 04:49
поделиться
Другие вопросы по тегам:

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