Son zamanlarda C bunu yapmak için bir makro yazdım, ama C ++ eşit derecede geçerli:
#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)
Herhangi bir türü kabul eder ve iletilen argümandaki baytları tersine çevirir. Örnek kullanımlar:
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]);
}
Hangi baskılar:
Before: ABCDEF0123456789
After : 8967452301EFCDAB
Before: nametag
After : gateman
Yukarıdakiler mükemmel bir şekilde kopyalayıp yapıştırabilir, ancak burada çok şey oluyor, bu yüzden parça parça nasıl çalıştığını parçalayacağım:
Dikkate değer ilk şey, tüm makronun bir do while(0)
blok içine yerleştirilmiş olmasıdır . Bu yaygın bir deyim makrodan sonra normal noktalı virgül kullanımına izin veren .
Bir sonraki adım, döngü sayacı REVERSE_BYTES
olarak adlandırılan bir değişkenin kullanılmasıdır for
. Makronun adı, makronun kullanıldığı her yerde kapsamda olabilecek herhangi bir sembolle çakışmamasını sağlamak için değişken adı olarak kullanılır. Ad, makronun genişletilmesinde kullanıldığından, burada değişken adı olarak kullanıldığında yeniden genişletilmez.
for
Döngü içinde, iki bayt başvuruda bulunur ve XOR değiştirilir (bu nedenle geçici bir değişken adı gerekli değildir):
((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES]
((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES]
__VA_ARGS__
makroya verilen her şeyi temsil eder ve aktarılabileceklerin esnekliğini arttırmak için kullanılır (çok fazla olmasa da). Bu argümanın adresi daha sonra alınır ve unsigned char
baytlarının dizi yoluyla değiştirilmesine izin vermek için bir işaretçiye gönderilir[]
aboneliği .
Son tuhaf nokta, {}
diş teli eksikliğidir . Gerekli değildir, çünkü her takastaki tüm adımlar virgül operatörü ile birleştirilir ve bu da onları bir ifade haline getirir.
Son olarak, hızın öncelikli olduğu durumlarda bunun ideal bir yaklaşım olmadığını belirtmek gerekir. Bu önemli bir faktörse, diğer yanıtlarda belirtilen türe özgü makroların veya platforma özgü yönergelerin bazıları muhtemelen daha iyi bir seçenektir. Ancak bu yaklaşım tüm türlere, tüm büyük platformlara ve hem C hem de C ++ dillerine taşınabilir.