Правда ли, что использование указателей значительно быстрее, чем использование синтаксиса массива в C? - PullRequest
3 голосов
/ 14 ноября 2010

С текущими компиляторами C все еще верно, что использование синтаксиса массива (a [i]) медленнее, чем использование указателей (* (p + i))?

Ответы [ 10 ]

11 голосов
/ 14 ноября 2010

Они в точности эквивалентны.Доступ к массиву - синтаксический сахар для математики указателя.

9 голосов
/ 14 ноября 2010

Они должны быть одинаковыми. Но:

for( i = 0; i < ...; ++ i ) ... array[i] ...

может быть медленнее, чем:

for( p = array; *p; ++ p ) ... *p ...

потому что в первом случае компилятору может потребоваться *(array+i), а во втором - просто (*p).

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

8 голосов
/ 14 ноября 2010

Нет, в соответствии со стандартами C и C ++ a[i] по определению эквивалентно *(a+i). это также означает, что a[1] эквивалентно 1[a]. Попробуйте:)

5 голосов
/ 14 ноября 2010

Черт, нет! a[i] всегда эквивалентно *(a+i).

a[i] = *(a + i) = *(i + a) =i[a];

3 голосов
/ 14 ноября 2010

В x86 или x86_64 использование p[i] или *(p+i) (примечание: эти две формы идентичны в языке C) может быть быстрее, чем увеличение p на каждом шаге цикла, при условии, что вам нужно сохранить i вокруг уже для какой-то другой цели.Архитектура x86 имеет эффективную адресацию для базового / смещенного использования, подобного этому, включая масштабирование смещения с малыми степенями 2.

С другой стороны, если вы можете исключить i, увеличив p, вы можетеуменьшите количество регистров, необходимых в цикле, что может позволить дальнейшую оптимизацию.Вот несколько быстрых рассуждений об относительной стоимости в различных случаях на x86:

  • Если у массива a есть статическая продолжительность хранения (static или extern global) в не-PIC-скомпилированномcode, методы a[i] и *p (без i) используют одинаковое количество регистров (например, 0xdeadbeef(,%ecx,4) против (%esi)).
  • Если ваш массив a автоматический (локальная переменная стека), а не массив переменной длины, методы a[i] и *p используют одинаковое количество регистров (например, 12(%esp,%ecx,4) против (%esi), где %esp, указатель стека, в любом случае, уже зарезервирован).
  • Если ваш массив a имеет статическую длительность хранения и ваш код скомпилирован как PIC, a[i], вероятно, значительно дороже, чем метод *p, даже если вам нужно хранить iв любом случае.
  • Если ваш массив a не является переменной массива в текущей области видимости, а является указателем на массив, переданный вашей функции откуда-то еще, тогда a[i] принимает еще один регистр, чем*p (например, (%eax,%ecx,4) против (%esi)).
2 голосов
/ 14 ноября 2010

Могут быть некоторые обстоятельства, когда что-то вроде

while (*s++ = *d++)
   ;

может быть быстрее, чем

while (s[i] = d[i])
   i++;

, но даже это, вероятно, будет оптимизировано хорошими компиляторами.

1 голос
/ 14 ноября 2010

Очевидно, что это не то, что он имеет в виду, это должно помочь.

// which is faster? *t or t[i]?
process_some_array(T *t, size_t n)
{
    T *end = &t[n];
    for (T *t = t; t < end; ++t)
        // do stuff with *t
    for (size_t i = 0; i < n; ++i)
        // do stuff with t[i]
}

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

Если это не то, что вы имели в виду, боюсь, это глупый вопрос, см. Один из других ответов.

1 голос
/ 14 ноября 2010

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

int a[];
for (int n = 0; n < size; n++) { ... Do stuff with a[n]; }

, что требует еще одного добавления для каждого доступа к элементу a, чем

int a[size];
int *end = a + size;
for (int *i = a; i != end; ++i) { ... Do the same stuff with *i ; }

Некоторые компиляторы могут оптимизировать первыйВерсия во второй, хотя.

1 голос
/ 14 ноября 2010

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

Думайте об операторе массива как о встроенной функции для эквивалентного указателя.

0 голосов
/ 09 июня 2013

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

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