Прежде всего, вы не должны обычно использовать символы с двойным подчеркиванием, поскольку они зарезервированы .
Символы, о которых вы говорите, не определяются компилятором, а являются частью вашей библиотеки C. bswap_XX
макросы могут использовать встроенную или даже встроенную сборку компилятора, чтобы компилятор генерировал специфичные для процессора инструкции, делая результат неизвестным во время компиляции.
Напротив, __bswap_constant_XX
должны оценивать значение с использованием простых выражений C, делая значение константой времени компиляции, если входные данные являются константой времени компиляции.
Такие макросы могут быть определены как:
#define __bswap_constant_16(x) \
((__uint16_t) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)))
#define __bswap_constant_32(x) \
((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >> 8) | \
(((x) & 0x0000ff00u) << 8) | (((x) & 0x000000ffu) << 24))
Идея состоит в том, что вы должны использовать __bswap_constant_XX
, когда вам нужно значение времени компиляции, например, при определении значения перечисления:
enum myenum {
MYVALUE = __bswap_constant_16(0x1234)
};
bswap_XX
предполагается использовать во всех других случаях.
Обратите внимание, что современный компилятор способен распознавать простые шаблоны замены байтов и генерировать соответствующие инструкции, поэтому на практике это не будет иметь большого значения большую часть времени.
Например, для обеих функций:
uint16_t bswap16(uint16_t x)
{
return __bswap_constant_16(x);
}
uint32_t bswap32(uint32_t x)
{
return __bswap_constant_32(x);
}
GCC 4.8.1 создает:
bswap16:
mov eax, edi
rol ax, 8
ret
bswap32:
mov eax, edi
bswap eax
ret