C переменное распределение времени и пространства - PullRequest
3 голосов
/ 08 июня 2011

Если у меня есть файл test.c со следующим

#include ...
int global = 0;

 int main() {
 int local1 = 0;

  while(1) {
  int local2 = 0;
  // Do some operation with one of them
 }
 return 0;
}

Итак, если бы мне пришлось использовать одну из этих переменных в цикле while, какая из них была бы предпочтительнее?

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

Ответы [ 5 ]

5 голосов
/ 08 июня 2011

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

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

2 голосов
/ 09 июня 2011

Существует три широких класса переменных: статические (глобальные), стек (авто) и регистр.

Переменные регистров хранятся в регистрах ЦП. Регистры - это очень быстрые запоминающие устройства размером в слово, которые интегрированы в конвейер ЦП. Они имеют свободный доступ, но их очень мало (обычно от 8 до 32 в зависимости от вашего процессора и операций, которые вы выполняете).

Переменные стека хранятся в области оперативной памяти, называемой стеком. Стек почти всегда будет находиться в кеше, поэтому переменным стека обычно требуется 1-4 цикла для доступа.

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

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

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


Редактировать: подробнее о распределении:

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

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

2 голосов
/ 08 июня 2011

Компилятору C будет легче оптимизировать переменные, объявленные локальными для функции. Глобальная переменная потребует оптимизатора для выполнения «межпроцедурного анализа потока данных», что обычно не делается.

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

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

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

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

2 голосов
/ 08 июня 2011

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

Как уже говорили и наверняка скажут другие, вряд ли будут какие-либо различия в производительности. Если они есть, автоматическая переменная будет быстрее.

2 голосов
/ 08 июня 2011

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

...