Почему не рекомендуется использовать указатель для доступа к массиву в C - PullRequest
4 голосов
/ 11 января 2020

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

https://www.cs.swarthmore.edu/~newhall/unixhelp/C_arrays.html#dynamic

Вы можете использовать арифметику указателя c (но, как правило, не)

рассмотрите следующий код в C

int    *p_array;
p_array = (int *)malloc(sizeof(int)*50);

for(i=0; i < 50; i++) {
  p_array[i] = 0;
}

В чем разница при использовании арифметики указателя c, подобного следующему коду (и почему это не рекомендуется) ?

int    *p_array;
p_array = (int *)malloc(sizeof(int)*50);      // allocate 50 ints

int *dptr = p_array;

for(i=0; i < 50; i++) {
  *dptr = 0;
  dptr++;
}

В каких случаях использование арифметических указателей c может вызвать проблемы в программном обеспечении? это плохая практика или неопытный инженер может не обращать внимания?

Ответы [ 3 ]

2 голосов
/ 20 января 2020

Так как в этом, похоже, все запутано:

В старые времена у нас были 16-битные процессоры 8088, 268 и c. Чтобы сформулировать адрес, вам нужно было загрузить свой сегментный регистр (16-битный регистр) и адресный регистр. при доступе к массиву вы можете загрузить базу массива в регистр сегмента, а регистр адреса будет индексом. C компиляторы для этих платформ существовали, но арифметика указателей c включала проверку адреса на предмет переполнений и, в случае необходимости, изменение регистра сегментов (неэффективно). Указатели с плоской адресацией просто не были возможны в аппаратном обеспечении.

Перемотка вперед до 80386 Теперь у нас есть полное 32-битное пространство. Возможны аппаратные указатели. Индекс + базовая адресация влечет за собой штраф за 1 такт. Сегменты также 32-битные, поэтому массивы можно загружать с использованием сегментов, избегая этого штрафа, даже если вы работаете в 32-битном режиме. Кроме того, 368 увеличивает количество регистров сегмента на 2. (Понятия не имею, почему Intel посчитала это хорошей идеей). Тем не менее, все еще было много 16-битного кода

В наши дни регистры сегментов отключены в 64-битных В режиме Base + Index адресация свободна.

Существует ли платформа, в которой плоский указатель может превзойти аппаратную адресацию массива? Ну да. Motorola 68000, выпущенный в 1979 году, имеет плоское 32-битное адресное пространство, без сегментов, а режим адресации Base + Index влечет за собой 8-тактный цикл за немедленную адресацию. Так что, если вы программируете станцию ​​Sun начала 80-х, Apple Lisa et c. это может быть актуально.

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

1 голос
/ 11 января 2020

Этот код не рекомендуется:

int    *p_array;
p_array = (int *)malloc(sizeof(int)*50);      // allocate 50 ints

int *dptr = p_array;

for(i=0; i < 50; i++) {
  *dptr = 0;
  dptr++;
}

, потому что 1) без причины у вас есть два разных указателя, которые указывают на одно и то же место, 2) вы не проверяете результат malloc() - - известно, что время от времени он возвращает NULL, 3) код не легко читается и 4) легко допустить глупую ошибку, которую потом трудно обнаружить.

В общем, я бы рекомендовал использовать это вместо:

int array[50] = { 0 };  // make sure it's zero-initialized
int* p_array = array;   // if you must =)
1 голос
/ 11 января 2020

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

Даже если вы программируете на платформе, в которой арифметика указателей c чем быстрее, тем больше вероятность того, что, если вы активируете оптимизацию компилятора ("-O3" на большинстве компиляторов), компилятор будет использовать любой метод, который является самым быстрым.

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

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

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

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