Скорость разыменования указателя структуры C - PullRequest
7 голосов
/ 21 октября 2010

У меня вопрос относительно скорости разыменования указателя.У меня есть такая структура:

typedef struct _TD_RECT TD_RECT;
struct _TD_RECT {
  double left;
  double top;
  double right;
  double bottom;
};

Мой вопрос: какой из них будет быстрее и почему?


Случай 1:

TD_RECT *pRect;
...
for(i = 0; i < m; i++)
{
   if(p[i].x < pRect->left) ...
   if(p[i].x > pRect->right) ...
   if(p[i].y < pRect->top) ...
   if(p[i].y > pRect->bottom) ...
}

CASE 2:

TD_RECT *pRect;
double left = pRect->left;
double top = pRect->top;
double right = pRect->right;
double bottom = pRect->bottom;
...
for(i = 0; i < m; i++)
{
   if(p[i].x < left) ...
   if(p[i].x > right) ...
   if(p[i].y < top) ...
   if(p[i].y > bottom) ...
}

Таким образом, в случае 1 цикл непосредственно разыменовывает указатель pRect для получения значений сравнения.В случае 2 новые значения были сделаны в локальном пространстве функции (в стеке), и значения были скопированы из pRect в локальные переменные.Через цикл будет много сравнений.

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

Кроме того, было бы лучше продолжать ссылаться на p [] по индексу или увеличивать p на один элемент и разыменовывать его напрямую без индекса.

Есть идеи?Спасибо:)

Ответы [ 5 ]

12 голосов
/ 21 октября 2010

Вы, вероятно, обнаружите, что это не будет иметь никакого значения с современными компиляторами. Большинство из них, вероятно, будут выполнять общее исключение подвыражений выражений, которые не изменяются в цикле. Неразумно предполагать, что между вашими операторами C и кодом сборки существует простое взаимно-однозначное соответствие. Я видел, как gcc выкачивает код, который опозорит мои навыки ассемблера.

Но это не вопрос C или C ++, поскольку стандарт ISO не предписывает, как это делается. Лучший способ убедиться в этом - сгенерировать код на ассемблере, например, gcc -S и подробно изучить два случая.

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

И, как и во всех вопросах оптимизации, измерьте, не угадайте! Слишком много переменных, которые могут повлиять на него, поэтому вы должны сравнить различные подходы в целевой среде и с реалистичными данными .

3 голосов
/ 21 октября 2010

Скорее всего, разница в производительности чрезвычайно мала. Вы могли бы профиль, делая каждый вариант несколько раз и посмотреть. Убедитесь, что в тесте настроены оптимизации вашего компилятора.

Что касается хранения парных чисел, вы можете получить некоторое снижение производительности, используя const. Насколько велик ваш массив?

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

Вы можете мгновенно оптимизировать, если вы знаете, что левый <правый в вашем прямоугольнике (конечно, это должно быть). Если x <left, он также не может быть> вправо, поэтому вы можете вставить «else».

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

Например, если вы проиндексировали или отсортировали свой массив по x и y, вы сможете, используя бинарный поиск, найти все значения, у которых есть x

1 голос
/ 21 октября 2010

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

Практически компилятор, выполняющий оптимизацию, может заметить это, и в разнице может не бытькод, который генерируется, но возможность pRect быть псевдонимом элемента в p [] может предотвратить это.

0 голосов
/ 21 октября 2010

Я буду удивлен, если даже полностью неоптимизированная компиляция (- O0) выдаст различный код для двух представленных случаев.Чтобы выполнить какую-либо операцию на современном процессоре, данные необходимо загрузить в регистры.Таким образом, даже когда вы объявляете автоматические переменные, эти переменные не будут существовать в основной памяти, а скорее в одном из регистров с плавающей запятой процессора.Это будет верно, даже если вы сами не объявляете переменные, и поэтому я не ожидаю никакой разницы в сгенерированном машинном коде, даже если вы объявляете временные переменные в своем коде C ++.

Но, как уже говорили другие, скомпилируйтекод в ассемблер и убедитесь сами.

0 голосов
/ 21 октября 2010

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

...