Представьте, что у меня есть такая структура:
struct GayClub {
...
int ndrinks;
...
}
И теперь я перебираю вот так:
// my struct
struct GayClub gc;
//....
// my loop
int i = 0;
for (; i < gc.ndrinks; ) {
...
// no modifications on gc.ndrinks
...
i++;
}
Вопрос в том, будет ли компилятор C, такой как GCC, cLang или Rusc? оптимизировать это так? Это быстрее, потому что я не удаляю ссылку на память.
// trick
int tmpNDrinks = gc.ndrinks;
// my za-loop-a
for (; i < tmpNDrinks; ) {
...
// no modifications on gc.ndrinks
...
i++;
}
Опять же, я спрашиваю об этом, потому что НЕ хочу каждый раз извлекать ограничения для отдельной переменной, если компилятор уже делает это за меня.
Кроме того: вы использовали синтаксис цикла for
как цикл while
, что делает код немного сложнее для чтения. Вы могли бы правильно соединить петлю for
, как for (int i = 0; i < gc.ndrinks; i++)
. Это зависит от того, что вам понадобится i
после цикла в невидимом коде.
@WeatherVane: Re: «В вашей предполагаемой оптимизации вы потратили время и пространство, копируя его из одного места памяти в другое»: Нет, предполагаемая оптимизация не тратит зря время и пространство. Стандарт C ничего не говорит о фактическом времени или пространстве, которые будут использоваться этой оптимизацией. int tmpNDrinks = gc.ndrinks;
создает новый объект, используя пространство и копируя память только внутри абстрактной машины, описанной стандартом C. Эта абстрактная машина существует только для того, чтобы определить семантику программы, а не для того, чтобы требовать фактического использования времени или пространства.
Это зависит от множества факторов, в том числе:
Будь то хороший компилятор.
Включили ли вы оптимизацию в компиляторе.
Видно ли компилятору, что объект не будет изменен другими способами.
Например, предположим, что тело цикла использует некоторый int *p
, который передается в качестве параметра или загружается из структуры данных. Если тело цикла содержит *p
, как компилятор узнает, указывает p
на gc.ndrinks
или нет? Если компилятор не может знать в качестве математического доказательства, что p
не указывает на gc.ndrinks
, тогда он должен генерировать код так, как если бы p
мог указывать на gc.ndrinks
.
Ваш пример неполон, поэтому читателю неясно, определен ли gc
внутри функции и имеет ли автоматическая продолжительность хранения. Если да, то компилятор может предположить, что параметр gc
не указывает на gc
, поскольку int *p
не существовало во время вызова функции. Однако если gc
не является параметром или если p
определен вне функции, компилятор может оказаться не в состоянии определить, что gc.ndrinks
не может указывать на int *p
.
Довольно часто, если вы хотите быть уверенным, что значение кэшируется на протяжении всего цикла, вам следует создать переменную для хранения этого значения. Это дешево, поскольку бремя отслеживания значения переменной ложится на компилятор, который оптимизирует ее использование. В чем суть.
В обоих случаях предел цикла находится в памяти, но при предполагаемой оптимизации вы потратили время и пространство, копируя его из одной области памяти в другую. Пожалуйста, посмотрите Действительно ли преждевременная оптимизация является корнем всех зол? Если вы считаете, что могут возникнуть проблемы с производительностью, профилируйте код, но такая микрооптимизация редко бывает необходима.