Что быстрее в длинном цикле - макрос или inline?

232
24 декабря 2017, 09:35

Например, есть цикл перевода YUY2 буфера в буфер BGR (от 100 до 900+ тысяч итераций):

OffsetBGR = 0;
while(OffsetYUY2 < VHDR->dwBufferLength){
    // Read from 4-byte YUY2 block
    Y1 = VHDR->lpData[OffsetYUY2++] -  16;
    U  = VHDR->lpData[OffsetYUY2++] - 128;
    Y2 = VHDR->lpData[OffsetYUY2++] -  16;
    V  = VHDR->lpData[OffsetYUY2++] - 128;
    // Record to 6-byte BGR block
    FrameData[OffsetBGR++] = GET_B(Y1, U, V);
    FrameData[OffsetBGR++] = GET_G(Y1, U, V);
    FrameData[OffsetBGR++] = GET_R(Y1, U, V);
    FrameData[OffsetBGR++] = GET_B(Y2, U, V);
    FrameData[OffsetBGR++] = GET_G(Y2, U, V);
    FrameData[OffsetBGR++] = GET_R(Y2, U, V);
}

... и есть алгоритмы получения отдельных элементов макросами:

#define CLAMP(t) ((t>255)?255:((t<0)?0:t))
// YUV to RGB
#define GET_R(Y,U,V) CLAMP(((298 * Y + 409 * V + 128) >> 8))
#define GET_G(Y,U,V) CLAMP(((298 * Y - 100 * U - 208 * V + 128) >> 8))
#define GET_B(Y,U,V) CLAMP(((298 * Y + 516 * U + 128) >> 8))

... или встраиваемыми функциями:

inline unsigned char clapm_byte(int value){return (value>255)?255:((value<0)?0:value);}
inline unsigned char R(char Y, char V){return clapm_byte((298 * Y + 409 * V + 128) >> 8);}
inline unsigned char G(char Y, char U, char V){return clapm_byte((298 * Y - 100 * U - 208 * V + 128) >> 8);}
inline unsigned char B(char Y, char U){return clapm_byte((298 * Y + 516 * U + 128) >> 8);}

Что в длинных циклах использовать эффективней с точки зрения производительности - макросы или встраиваемые функции? И нормально ли использовать inline в inline-е, если функция небольшая?

Answer 1

Нет никакой разницы с точки зрения производительности, так как код inline-функции в c++ на этапе компиляции вставляется туда, где она была вызвана. Тонкости, конечно, зависят от компилятора.

Разница же будет в том, что для inline функций компилятор дополнительно генерирует некоторый код, который поможет избежать некоторых проблем, возникающих с #define. Например:

#define addTwoSameNumbers(a) a + a

А после вы вызываете это так:

addTwoSameNumbers(++a)

И в итоге код, который добавит компилятор, будет иметь вид:

++a + ++a

И тогда переменная a будет увеличена дважды. С inline функциями таких проблем нет, так как об этом заботится компилятор.

Англоязычный ответ: https://stackoverflow.com/questions/3554527/whats-the-difference-in-practice-between-inline-and-define

Answer 2

Разнице в смысле функций нет, и компилятор уже давно научился подставлять inline-функции в точку вызова там, где это приносит выгоду.

Однако, с макросами намного проще ошибиться. Например, в ваших макросах есть типичная ошибка:

#define GET_R(Y,U,V) CLAMP(((298 * Y + 409 * V + 128) >> 8))

Представьте себе, что кто-то вызовет

GET_R(old_Y + 1, old_V + 1, old_R + 1)

Это раскроется в

CLAMP(((298 * old_Y + 1 + 409 * old_V + 1 + 128) >> 8))

Отлаживать такую ошибку будет ой как непросто, и компилятор об этом не предупредит. Поэтому имеет смысл не пользоваться макросами без крайней, реальной на то необходимости.

READ ALSO
Замена strcpy и ошибки C4996, E0304, C2660

Замена strcpy и ошибки C4996, E0304, C2660

Как можно заменить strcpy не теряя работоспособности?

987
Найти максимальные элементы в матрице

Найти максимальные элементы в матрице

Нужно найти максимальные элементы в матрице и вывести их отдельно Код есть, но не знаю как доработать

220
QSlider C++ трекинг

QSlider C++ трекинг

Как при изменении значения слайдера вызывать определённый метод? Пробовал вот так, но CLion выдаёт ошибку:

217
Запуск программы с запуском Windows

Запуск программы с запуском Windows

Есть программаИнтересно, как сделать так, чтобы она запускалась вместе с Windows? Поместить ярлык в автозапуск не подходит

215