Есть ли различие в производительности, если Вы любой делает myarray[ i ]
или сохраните адрес myarray[ i ]
в указателе?
Править: Указатели все вычисляются во время неважного шага в моей программе, где производительность не является никакими критериями. Во время критических частей указатели остаются статичными и не изменяются. Теперь вопрос состоит в том, если эти статические указатели быстрее, чем использование myarray[ i ]
все время.
Не должно быть больших различий , но , используя индексирование, вы избегаете всех типов различных ловушек, которым подвержен оптимизатор компилятора (наиболее важным из них является псевдонимание) и, таким образом, Я бы сказал, что компилятору должно быть проще обрабатывать случай индексации. Это не означает, что вы должны позаботиться о вышеупомянутых вещах перед циклом, но указатели в цикле обычно просто добавляют сложности.
Да. При наличии указателя адрес не будет вычисляться с использованием начального адреса массива. Он будет доступен напрямую. Таким образом, вы немного улучшите производительность, если сохраните адрес в указателе. Но компилятор обычно оптимизирует код и использует указатель в обоих случаях (если у вас есть статические массивы)
Для динамических массивов (созданных с помощью new
) указатель обеспечивает большую производительность, поскольку компилятор не может оптимизировать доступ к массиву во время компиляции.
Краткий ответ: единственный способ узнать наверняка - это закодировать обе версии и сравнить производительность. Я лично был бы удивлен, если бы наблюдалась измеримая разница, если бы вы не выполняли много обращений к массиву в очень плотном цикле. Если это происходит один или два раза за время существования программы или зависит от ввода данных пользователем, не стоит беспокоиться.
Помните, что выражение a [i]
вычисляется как * (a + i)
, что является сложением плюс разыменование, тогда как * p
это просто разыменование. Однако в зависимости от того, как структурирован код, это может не иметь значения. Предположим следующее:
int a[N]; // for any arbitrary N > 1
int *p = a;
size_t i;
for (i = 0; i < N; i++)
printf("a[%d] = %d\n", i, a[i]);
for (i = 0; i < N; i++)
printf("*(%p) = %d\n", (void*) p, *p++);
Теперь мы сравниваем a [i]
с * p ++
, что является разыменованием плюс постинкремент (в дополнение к i ++
] в контуре управления); это может оказаться более затратной операцией, чем индекс массива. Не говоря уже о том, что мы ввели еще одну переменную, которая не является строго необходимой; мы продаем немного места на то, что может или не может быть улучшением скорости. Это действительно зависит от компилятора, структуры кода, настроек оптимизации, ОС и процессора.
В первую очередь беспокоиться о правильности , затем беспокоиться о удобочитаемости / ремонтопригодности, затем беспокоиться о безопасности / надежности, а затем беспокоиться о производительности. Если вы не выполняете жесткие требования к производительности, сосредоточьтесь на том, чтобы ваши намерения были ясными и понятными.Неважно, насколько быстро ваш код, если он дает неправильный ответ или выполняет неправильное действие, или если он ужасно вылетает при первом намеке на неправильный ввод, или если вы не можете исправить ошибки или добавить новые функции, не нарушая что-то.
Да .. при сохранении указателя myarray [i]
он будет работать лучше (при использовании в больших масштабах ...)
Почему ??
Это сохранит вам сложение и может быть умножением (или сдвигом ..)
Многие компиляторы могут оптимизировать это для вас в случае распределения статической памяти. Если вы используете динамическое выделение памяти, компилятор не будет его оптимизировать, потому что он находится во время выполнения!
Для этого кода:
int main() {
int a[100], b[100];
int * p = b;
for ( unsigned int i = 0; i < 100; i++ ) {
a[i] = i;
*p++ = i;
}
return a[1] + b[2];
}
при сборке с оптимизацией -O3 в g++, оператор:
a[i] = i;
выдал на выходе ассемблер:
mov %eax,(%ecx,%eax,4)
а этот оператор:
*p++ = i;
выдал:
mov %eax,(%edx,%eax,4)
Так что в данном случае разницы между ними не было. Однако это не является и не может быть общим правилом - оптимизатор вполне может сгенерировать совершенно другой код даже для немного отличающихся входных данных.
Это, вероятно, вообще не будет иметь никакого значения. Компилятор, как правило, достаточно умен, чтобы знать, когда вы используете выражение более одного раза, и при необходимости сам создавать временное.
Компиляторы могут делать неожиданные оптимизации; единственный способ узнать это - прочитать сгенерированный ассемблерный код.
В GCC используйте -S
, с -masm = intel
для синтаксиса Intel.
В VC ++ используйте / FA
(IIRC).
Вы также должны включить оптимизацию: -O2
или -O3
с GCC и / O2
с VC ++.
Я предпочитаю использовать myarray[ i ]
, так как это более понятно, и компилятору легче скомпилировать это в оптимизированный код.
При использовании указателей компилятору сложнее оптимизировать этот код, так как труднее понять, что именно вы делаете с указателем.
Существенной разницы не будет. Преждевременная оптимизация - это корень всех зол - получите профилировщик, прежде чем проверять такие микрооптимизации. Кроме того, myarray [i] более портативен для пользовательских типов, таких как std :: vector.
Хорошо, так что ваш вопрос в том, что быстрее:
int main(int argc, char **argv)
{
int array[20];
array[0] = 0;
array[1] = 1;
int *value_1 = &array[1];
printf("%d", *value_1);
printf("%d", array[1]);
printf("%d", *(array + 1));
}
Как уже отмечалось, компиляторы могут делать умную оптимизацию. Конечно, это зависит от того, где используется выражение, но обычно вы не должны беспокоиться об этих тонких различиях. Все ваши предположения могут быть опровергнуты компилятором. Сегодня не стоит беспокоиться о таких различиях.
Например, приведенный выше код дает следующий (только фрагмент):
mov [ebp+var_54], 1 #store 1
lea eax, [ebp+var_58] # load the address of array[0]
add eax, 4 # add 4 (size of int)
mov [ebp+var_5C], eax
mov eax, [ebp+var_5C]
mov eax, [eax]
mov [esp+88h+var_84], eax
mov [esp+88h+var_88], offset unk_403000 # points to %d
call printf
mov eax, [ebp+var_54]
mov [esp+88h+var_84], eax
mov [esp+88h+var_88], offset unk_403000
call printf
mov eax, [ebp+var_54]
mov [esp+88h+var_84], eax
mov [esp+88h+var_88], offset unk_403000
call printf