Я недавно написал макрос для этого в C, но он одинаково действителен и в C ++:
#define REVERSE_BYTES(...) do for(size_t REVERSE_BYTES=0; REVERSE_BYTES<sizeof(__VA_ARGS__)>>1; ++REVERSE_BYTES)\
((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES],\
((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES],\
((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES];\
while(0)
Он принимает любой тип и переворачивает байты в переданном аргументе. Пример использования:
int main(){
unsigned long long x = 0xABCDEF0123456789;
printf("Before: %llX\n",x);
REVERSE_BYTES(x);
printf("After : %llX\n",x);
char c[7]="nametag";
printf("Before: %c%c%c%c%c%c%c\n",c[0],c[1],c[2],c[3],c[4],c[5],c[6]);
REVERSE_BYTES(c);
printf("After : %c%c%c%c%c%c%c\n",c[0],c[1],c[2],c[3],c[4],c[5],c[6]);
}
Какие отпечатки:
Before: ABCDEF0123456789
After : 8967452301EFCDAB
Before: nametag
After : gateman
Вышесказанное прекрасно подходит для копирования / вставки, но здесь многое происходит, поэтому я расскажу, как это работает по частям:
Первая заметная вещь заключается в том, что весь макрос заключен в do while(0)
блок. Это распространенная идиома разрешающая нормальное использование точки с запятой после макроса.
Следующим является использование переменной с именем в REVERSE_BYTES
качестве for
счетчика цикла в. Имя самого макроса используется в качестве имени переменной, чтобы гарантировать, что он не конфликтует с любыми другими символами, которые могут находиться в области видимости везде, где используется макрос. Поскольку имя используется в расширении макроса, оно не будет расширено снова при использовании здесь в качестве имени переменной.
Внутри for
цикла есть два байта, на которые ссылаются и которые меняются местами XOR (поэтому временное имя переменной не требуется):
((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES]
((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES]
__VA_ARGS__
представляет все, что было дано макросу, и используется для увеличения гибкости того, что может быть передано (хотя и ненамного). Адрес этого аргумента затем берется и приводится к unsigned char
указателю, чтобы разрешить обмен его байтов посредством []
подписки массива .
Последний специфический момент - отсутствие {}
скобок. В них нет необходимости, поскольку все шаги в каждом свопе объединяются с помощью оператора запятой , что делает их одним оператором.
Наконец, стоит отметить, что это не идеальный подход, если скорость является главным приоритетом. Если это важный фактор, некоторые из макросов, специфичных для типа, или директив, специфичных для платформы, на которые есть ссылки в других ответах, вероятно, являются лучшим вариантом. Этот подход, однако, переносим для всех типов, всех основных платформ и языков C и C ++.