ANSI C # определить функции VS - PullRequest
4 голосов
/ 13 октября 2011

У меня есть вопрос по поводу производительности моего кода. Допустим, у меня есть структура в C для точки:

typedef struct _CPoint
{
    float x, y;
} CPoint;

и функция, в которой я использую структуру.

float distance(CPoint p1, CPoint p2)
{
    return sqrt(pow((p2.x-p1.x),2)+pow((p2.y-p1.y),2));
}

Мне было интересно, будет ли разумно заменить эту функцию на # define,

#define distance(p1, p2)(sqrt(pow((p2.x-p1.x),2)+pow((p2.y-p1.y),2)));

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

Должен ли я заменить все свои функции на #define для повышения производительности моего кода?

Ответы [ 5 ]

8 голосов
/ 13 октября 2011

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

Макросы имеют множество скрытых недостатков, которые могут вас укусить.В данном случае ваш перевод в макрос здесь некорректен (или, по крайней мере, семантика не сохраняется с исходной функцией).Аргумент макроса distance оценивается 2 раза каждый.Представьте, что я сделал следующий вызов

distance(GetPointA(), GetPointB());

В макро-версии это фактически приводит к 4 вызовам функций, потому что каждый аргумент оценивается дважды.Если бы distance было оставлено как функция, это привело бы только к 3 вызовам функции (расстояние и каждый аргумент).Примечание: я игнорирую влияние sqrt и pow в приведенных выше вычислениях, поскольку они одинаковы в обеих версиях.

3 голосов
/ 13 октября 2011

Джаред прав, и в этом конкретном случае циклы, потраченные на вызовы pow и вызов sqrt, будут в диапазоне на 2 порядка больше, чем циклы, потраченные на вызов distance.

Иногда люди считают, что маленький код равен маленькому времени.Не так.

3 голосов
/ 13 октября 2011

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

inline float distance(CPoint p1, CPoint p2)
{
    float dx = p2.x - p1.x;
    float dy = p2.y - p1.y;
    return sqrt(dx*dx + dy*dy);
}

(Заметьте, я также заменил pow(dx, 2) на dx * dx. Оба эквивалентны, и умножение с большей вероятностью будет эффективным. Некоторые компиляторы могут попытаться оптимизировать вызов до pow ... но угадайте, что они замените его на.)

3 голосов
/ 13 октября 2011

Есть три вещи:

  • нормальные функции, такие как distance выше
  • встроенные функции
  • макросы препроцессора
1 голос
/ 13 октября 2011

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

Для gcc -O3 или (для «маленьких» функций) даже опция -O2 сделает это.

Подробнее об этом вы можете прочитать здесь http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html для параметров "-finline *".

...