C и C++: указатель Доступа к элементу массива по сравнению с интервалом

Есть ли различие в производительности, если Вы любой делает myarray[ i ] или сохраните адрес myarray[ i ] в указателе?

Править: Указатели все вычисляются во время неважного шага в моей программе, где производительность не является никакими критериями. Во время критических частей указатели остаются статичными и не изменяются. Теперь вопрос состоит в том, если эти статические указатели быстрее, чем использование myarray[ i ] все время.

5
задан begun 18 May 2010 в 12:26
поделиться

10 ответов

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

1
ответ дан 18 December 2019 в 08:27
поделиться

Да. При наличии указателя адрес не будет вычисляться с использованием начального адреса массива. Он будет доступен напрямую. Таким образом, вы немного улучшите производительность, если сохраните адрес в указателе. Но компилятор обычно оптимизирует код и использует указатель в обоих случаях (если у вас есть статические массивы)

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

0
ответ дан 18 December 2019 в 08:27
поделиться

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

Помните, что выражение 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 ++ ] в контуре управления); это может оказаться более затратной операцией, чем индекс массива. Не говоря уже о том, что мы ввели еще одну переменную, которая не является строго необходимой; мы продаем немного места на то, что может или не может быть улучшением скорости. Это действительно зависит от компилятора, структуры кода, настроек оптимизации, ОС и процессора.

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

0
ответ дан 18 December 2019 в 08:27
поделиться

Да .. при сохранении указателя myarray [i] он будет работать лучше (при использовании в больших масштабах ...)

Почему ??

Это сохранит вам сложение и может быть умножением (или сдвигом ..)

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

-1
ответ дан 18 December 2019 в 08:27
поделиться

Для этого кода:

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)

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

8
ответ дан 18 December 2019 в 08:27
поделиться

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

4
ответ дан 18 December 2019 в 08:27
поделиться

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

В GCC используйте -S , с -masm = intel для синтаксиса Intel.

В VC ++ используйте / FA (IIRC).

Вы также должны включить оптимизацию: -O2 или -O3 с GCC и / O2 с VC ++.

4
ответ дан 18 December 2019 в 08:27
поделиться

Я предпочитаю использовать myarray[ i ], так как это более понятно, и компилятору легче скомпилировать это в оптимизированный код.

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

3
ответ дан 18 December 2019 в 08:27
поделиться

Существенной разницы не будет. Преждевременная оптимизация - это корень всех зол - получите профилировщик, прежде чем проверять такие микрооптимизации. Кроме того, myarray [i] более портативен для пользовательских типов, таких как std :: vector.

0
ответ дан 18 December 2019 в 08:27
поделиться

Хорошо, так что ваш вопрос в том, что быстрее:

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
0
ответ дан 18 December 2019 в 08:27
поделиться