Постоянный указатель массива или указатель на массив?Что быстрее в С? - PullRequest
3 голосов
/ 25 января 2011

Здравствуйте, я сейчас нахожусь в промежуточном классе C, и мне в голову пришла эта мысль:

int multi[3][4]; // const multidimensional array

int* ptr = *multi; // ptr is a pointer variable that hold the address of multi const array

Итак, что быстрее / меньше / оптимизировано для доступа к позиции многомерного массива?

Это:

multi[3][1]; // index the value position

или

*(*(multi+2)+1); // pointer to the position on the array

или (ОБНОВЛЕНО)

ptr += 9; // pointer arithmetic using auxiliary pointer

Поскольку "multi" является константным массивом, компилятор должен "Я знаю, что уже локализация позиции элемента, в случае использования указателя переменной, указывающего на этот массив, который может занять больше времени обработки, с другой стороны, может быть быстрее при поиске элемента, который я хочу отобразить.Какой подход быстрее / меньше / оптимизирован?

Заранее спасибо.

Ответы [ 5 ]

8 голосов
/ 25 января 2011

Они все скомпилированы одинаково, *(pointer_to_first_element + x + y).

6 голосов
/ 25 января 2011

Во-первых,

int multi[3][4];

- это не массив const.В этом объявлении нет ничего const.

Во-вторых,

int* ptr = *multi;

заставит ptr указать на элемент multi[0][0].Численно он совпадает с адресом multi[0] и адресом всего multi, но типы различаются.

В-третьих,

multi[3][1];

по определению одинаковкак

*(*(multi + 3) + 1);

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

В-четвертых,

*ptr + 9;

не имеет в себе никакой «арифметики указателей».Это эквивалентно

multi[0][0] + 9;

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

Наконец, ваш вопрос называется «Массив постоянных указателей или указатель на массив», хотя в реальном тексте вопроса я не вижу.

4 голосов
/ 25 января 2011

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

Например:

int main(void)
{
  int arr[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}};
  int *p = *arr; // == arr[0] == &arr[0][0]

  int x;

  x = arr[2][3];         // Straightforward array access
  x = *(*(arr+2)+3);     // Ugly pointer arithmetic
  x = *(ptr + 11);       // Slightly less ugly pointer arithmetic

  return 0;
}

Я запустил вышеупомянутое через gcc -c -g -Wa,-a,-ad > foo.lst, чтобы сгенерировать сгенерированную сборку и исходный код.

Вот перевод x = arr[2][3];:

movl      -16(%ebp), %eax     
movl      %eax, -8(%ebp)      

Вот перевод x = *(*(arr+2)+3);:

leal      -60(%ebp), %eax
addl      $44, %eax
movl      (%eax), %eax
movl      %eax, -8(%ebp)

И, наконец, перевод x = *(ptr + 11);:

movl      -12(%ebp), %eax
addl      $44, %eax
movl      (%eax), %eax
movl      %eax, -8(%ebp)

Не пытайтесь перехитрить ваш компилятор . Это уже не 1970-е годы. gcc знает, как эффективно осуществлять доступ к массивам, не сообщая об этом.

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

EDIT

Естественно, когда литералы 2 и 3 заменяются переменными, ситуация меняется. В этом случае *(ptr + offset); выглядит лучше всего. Но не очень. И я все еще буду утверждать, что ясность важнее на этом уровне.

2 голосов
/ 25 января 2011

a[i] означает *(a+i), фактически вы также можете написать i[a] и ваш компилятор примет это.

*(ptr+i) в любом случае может быть немного быстрее, чем ptr[j][k] в теории, поскольку вы делаете одно добавление (тогда как ptr[j][k] может потребовать 2).

1 голос
/ 25 января 2011

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

Поскольку в оригинальном постере явно не упоминалось программирование на ПК, константные массивыи регулярные массивы не обязательно компилируются одинаково.

Во встроенных системах const-массивы могут быть медленнее, чем неконстантные, если массивы const размещены в истинной энергонезависимой памяти, то есть во встроенном приложении с реальным ПЗУ.Замедление связано со временем доступа к ПЗУ и сильно зависит от оборудования.


Что касается арифметики указателей, то это единственный способ доступа к массивам.Синтаксис массива в языке C - это то, что люди называют компилятором «синтаксическим сахаром», то есть он только для внешнего вида.Доступ к массиву, такой как

arr [i]

, переводится компилятором в

* (arr + i)

, и они эквивалентны по производительностии функция.

...