Эффективность: массивы против указателей - PullRequest
56 голосов
/ 21 февраля 2010

Доступ к памяти через указатели считается более эффективным, чем доступ к памяти через массив. Я изучаю C, и вышеизложенное указано в K & R. В частности, они говорят,

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

Я разобрал следующий код, используя Visual C ++. (У меня процессор 686. Я отключил все оптимизации.)

int a[10], *p = a, temp;

void foo()
{
    temp = a[0];
    temp = *p;
}

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

; 5    : temp = a[0];

    mov eax, DWORD PTR _a
    mov DWORD PTR _temp, eax

; 6    : temp = *p;

    mov eax, DWORD PTR _p
    mov ecx, DWORD PTR [eax]
    mov DWORD PTR _temp, ecx

Пожалуйста, помогите мне понять. Что мне здесь не хватает ??


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

; 7    :        temp = a[i];

    mov eax, DWORD PTR _i
    mov ecx, DWORD PTR _a[eax*4]
    mov DWORD PTR _temp, ecx

; 8    : 
; 9    :    
; 10   :        temp = *p;

    mov eax, DWORD PTR _p
    mov ecx, DWORD PTR [eax]
    mov DWORD PTR _temp, ecx

Ответы [ 13 ]

1 голос
/ 21 февраля 2010

Поскольку 0 определяется как константа, a [0] также является константой, и компилятор знает, где она находится во время компиляции. В «нормальном» случае компилятор должен будет вычислить адрес элемента по основанию + смещение (с масштабированием смещения в соответствии с размером элемента).

OTOH, p - переменная, и косвенное направление требует дополнительного хода.

В общем случае индекс массива внутренне обрабатывается как арифметика указателей, так что я не уверен, что вижу смысл, который K & R пытался объяснить.

1 голос
/ 21 февраля 2010

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

В вашем случае вам нужно включить оптимизацию, чтобы получить тот же результат.

0 голосов
/ 06 июня 2018

Я немного удивлен, что ptr быстрее, чем обсуждение массива, где доказательства того, что это не так, изначально даются кодом asm из Abhijith.

mov eax, dord ptr _a; // загрузить непосредственно значение из адреса _a

против

mov eax, dword ptr _p; // загрузка адреса / значения p в eax

и

mov ecx, dword ptr [eax]; // использовать загруженный адрес для доступа к значению и поместить в ecx

Массив представляет собой фиксированный адрес, поэтому процессор может напрямую обращаться к нему, но не так, как с ptr, для которого процессор должен получить доступ к значению!

Вторая партия кода не может быть скомбинирована, так как смещение массива должно быть рассчитано, чтобы сделать это для ptr, вам также потребуется как минимум еще 1/2 инструкции!

Все, что компилятор может вывести во время компиляции (фиксированные адреса, смещения и т. Д.), Является ключом к коду исполняемого кода. Сравнение итеративного кода и присвоение переменным:

Массив:

; 2791: tmp = buf_ai [l];

mov eax, DWORD PTR _l$[ebp]
mov ecx, DWORD PTR _buf_ai$[ebp+eax*4]
mov DWORD PTR _tmp$[ebp], ecx

против

PTR

; 2796: tmp2 = * p;

mov eax, DWORD PTR _p$[ebp]
mov ecx, DWORD PTR [eax]
mov DWORD PTR _tmp2$[ebp], ecx

плюс

; 2801: ++ p;

mov eax, DWORD PTR _p$[ebp]
add eax, 4
mov DWORD PTR _p$[ebp], eax

Это просто для адреса загрузки ptr в первую очередь, чем использовать его по сравнению с массивом, используя адрес и получить значение одновременно!

С наилучшими пожеланиями

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...