如何反转字节顺序?
How to reverse endianness?
谁能帮我理解这段代码?
int reverse_endianess(int value) {
int resultat = 0;
char *source, *destination;
int i;
source = (char *) &value;
destination = ((char *) &resultat) + sizeof(int);
for (i = 0; i < sizeof(int); i++)
*(--destination) = *(source++);
return resultat;
}
我无法理解这部分代码:
destination = ((char *) &resultat) + sizeof(int);
for (i = 0; i < sizeof(int); i++)
*(--destination) = *(source++);
以下导致 destination
指向 resultat
之后的字节(只要 resultat
是一个 int
):
destination = ((char *) &resultat) + sizeof(int);
也可以这样写:
destination = (char *)(&resultat + 1);
下面只是一个简单的内存复制循环:
for (i = 0; i < sizeof(int); i++)
*(--destination) = *(source++);
等同于:
for (i = 0; i < sizeof(int); i++) {
--destination; // Point to the one byte earlier.
*destination = *source; // Copy one byte.
source++; // Point to one byte later.
}
程序流程(假设32位int
和8位char
)
设置后:
source value
+----------+ +---+---+---+---+
| -------+ | a | b | c | d |
+----------+ | +---+---+---+---+
| ^
+------+
destination resultat
+----------+ +---+---+---+---+
| -------+ | 0 | 0 | 0 | 0 |
+----------+ | +---+---+---+---+
| ^
+----------------------+
循环一次后:
source value
+----------+ +---+---+---+---+
| -------+ | a | b | c | d |
+----------+ | +---+---+---+---+
| ^
+----------+
destination resultat
+----------+ +---+---+---+---+
| -------+ | 0 | 0 | 0 | a |
+----------+ | +---+---+---+---+
| ^
+------------------+
完成后:
source value
+----------+ +---+---+---+---+
| -------+ | a | b | c | d |
+----------+ | +---+---+---+---+
| ^
+----------------------+
destination resultat
+----------+ +---+---+---+---+
| -------+ | d | c | b | a |
+----------+ | +---+---+---+---+
| ^
+------+
让我们说 sizeof(int) = 4
所以 32 位 int。
一个 char 是 sizeof 1,1 个字节。
一个普通的 int* 看起来像这样:
aabbccdd // the int in hexadecimal
^ pointer points to start
如果我们将其转换为 char*,我们会得到 aa
。这就是 source
.
所做的
如果我们现在添加 sizeof 4,我们向右跳转 4 个字节:
aabbccdd??
^
我们现在落后于该值一个字节,访问它可能会导致程序段错误或只是读取垃圾。由于使用 --destination
而不是 destination--
,因此不会发生这种情况。它首先递减。
现在我们只是从前面读取传入的整数,从后面写入:
a1b2c3d4 // original int
->
d4c3b2a1 // destination
<-
注意两个十六进制数是一个字节,这就是为什么我们没有得到
4d3c2b1a
。我们以正确的方式保留字节,但将第一个字节放在最后。
三种不同的方法。第一种在有字节反转指令的系统上效率最高。
#define SWAPUC(a,b) do{unsigned char temp = (a); (a) = (b); (b) = temp;}while(0)
int reverse(int i)
{
unsigned int val = i;
if(sizeof(val) == 4)
val = ((val & 0xff) << 24) | ((val & 0xff00) << 8) | ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24);
if(sizeof(val) == 8)
val = ((val & 0x00000000000000ffULL) << 56) | ((val & 0xff00000000000000ULL) >> 56) |
((val & 0x000000000000ff00ULL) << 40) | ((val & 0x00ff000000000000ULL) >> 40) |
((val & 0x0000000000ff0000ULL) << 24) | ((val & 0x0000ff0000000000ULL) >> 24) |
((val & 0x00000000ff000000ULL) << 8) | ((val & 0x000000ff00000000ULL) >> 8);
return val;
}
int reverse1(int val)
{
union
{
unsigned i;
unsigned char uc[sizeof(val)];
}uni = {.i = val};
if(sizeof(val) == 8)
{
SWAPUC(uni.uc[7], uni.uc[0]);
SWAPUC(uni.uc[6], uni.uc[1]);
SWAPUC(uni.uc[5], uni.uc[2]);
SWAPUC(uni.uc[4], uni.uc[3]);
}
if(sizeof(val) == 4)
{
SWAPUC(uni.uc[3], uni.uc[0]);
SWAPUC(uni.uc[2], uni.uc[1]);
}
return uni.i;
}
int reverse2(int val)
{
unsigned char uc[sizeof(val)];
memcpy(uc, &val, sizeof(uc));
if(sizeof(val) == 8)
{
SWAPUC(uc[7], uc[0]);
SWAPUC(uc[6], uc[1]);
SWAPUC(uc[5], uc[2]);
SWAPUC(uc[4], uc[3]);
}
if(sizeof(val) == 4)
{
SWAPUC(uc[3], uc[0]);
SWAPUC(uc[2], uc[1]);
}
memcpy(&val, uc, sizeof(uc));
return val;
}
int main(void)
{
printf("%x\n", reverse2(0xaabbccdd));
}
生成的代码(x86):
reverse:
mov eax, edi
bswap eax
ret
reverse1:
mov eax, edi
xor edx, edx
mov ecx, edi
shr eax, 24
movzx esi, ch
sal ecx, 24
mov dl, al
mov eax, edi
sal esi, 16
shr eax, 16
mov dh, al
movzx eax, dx
or eax, esi
or eax, ecx
ret
reverse2:
mov eax, edi
xor edx, edx
mov ecx, edi
shr eax, 24
movzx esi, ch
sal ecx, 24
mov dl, al
mov eax, edi
sal esi, 16
shr eax, 16
mov dh, al
movzx eax, dx
or eax, esi
or eax, ecx
ret
.LC0:
.string "%x\n"
或者cortex M4(这个有字节交换指令)
reverse:
rev r0, r0
bx lr
reverse1:
mov r3, r0
lsrs r2, r3, #24
movs r0, #0
bfi r0, r2, #0, #8
ubfx r2, r3, #16, #8
bfi r0, r2, #8, #8
ubfx r2, r3, #8, #8
bfi r0, r2, #16, #8
bfi r0, r3, #24, #8
bx lr
reverse2:
mov r3, r0
lsrs r2, r3, #24
movs r0, #0
bfi r0, r2, #0, #8
ubfx r2, r3, #16, #8
bfi r0, r2, #8, #8
ubfx r2, r3, #8, #8
bfi r0, r2, #16, #8
bfi r0, r3, #24, #8
bx lr
.LC0:
因此获胜者是第一个仅使用按位算术的函数。
我已经用了很长时间了。
数据是指向要反转的值的指针
n 是要反转的字符数;通常 2、4、8 表示 short、int、long long。
但这在各种 architectures/OS
上可能会有所不同
void SwapEndianN(char *data, unsigned short n) {
unsigned short k; char c;
for ( k=0 ; k < (n/2) ;k++ ) {
c = *(data+((n-1)-k));
*(data+((n-1)-k)) = *(data+k);
*(data+k) = c;
}
}
谁能帮我理解这段代码?
int reverse_endianess(int value) {
int resultat = 0;
char *source, *destination;
int i;
source = (char *) &value;
destination = ((char *) &resultat) + sizeof(int);
for (i = 0; i < sizeof(int); i++)
*(--destination) = *(source++);
return resultat;
}
我无法理解这部分代码:
destination = ((char *) &resultat) + sizeof(int);
for (i = 0; i < sizeof(int); i++)
*(--destination) = *(source++);
以下导致 destination
指向 resultat
之后的字节(只要 resultat
是一个 int
):
destination = ((char *) &resultat) + sizeof(int);
也可以这样写:
destination = (char *)(&resultat + 1);
下面只是一个简单的内存复制循环:
for (i = 0; i < sizeof(int); i++)
*(--destination) = *(source++);
等同于:
for (i = 0; i < sizeof(int); i++) {
--destination; // Point to the one byte earlier.
*destination = *source; // Copy one byte.
source++; // Point to one byte later.
}
程序流程(假设32位int
和8位char
)
设置后:
source value
+----------+ +---+---+---+---+
| -------+ | a | b | c | d |
+----------+ | +---+---+---+---+
| ^
+------+
destination resultat
+----------+ +---+---+---+---+
| -------+ | 0 | 0 | 0 | 0 |
+----------+ | +---+---+---+---+
| ^
+----------------------+
循环一次后:
source value
+----------+ +---+---+---+---+
| -------+ | a | b | c | d |
+----------+ | +---+---+---+---+
| ^
+----------+
destination resultat
+----------+ +---+---+---+---+
| -------+ | 0 | 0 | 0 | a |
+----------+ | +---+---+---+---+
| ^
+------------------+
完成后:
source value
+----------+ +---+---+---+---+
| -------+ | a | b | c | d |
+----------+ | +---+---+---+---+
| ^
+----------------------+
destination resultat
+----------+ +---+---+---+---+
| -------+ | d | c | b | a |
+----------+ | +---+---+---+---+
| ^
+------+
让我们说 sizeof(int) = 4
所以 32 位 int。
一个 char 是 sizeof 1,1 个字节。
一个普通的 int* 看起来像这样:
aabbccdd // the int in hexadecimal
^ pointer points to start
如果我们将其转换为 char*,我们会得到 aa
。这就是 source
.
如果我们现在添加 sizeof 4,我们向右跳转 4 个字节:
aabbccdd??
^
我们现在落后于该值一个字节,访问它可能会导致程序段错误或只是读取垃圾。由于使用 --destination
而不是 destination--
,因此不会发生这种情况。它首先递减。
现在我们只是从前面读取传入的整数,从后面写入:
a1b2c3d4 // original int
->
d4c3b2a1 // destination
<-
注意两个十六进制数是一个字节,这就是为什么我们没有得到
4d3c2b1a
。我们以正确的方式保留字节,但将第一个字节放在最后。
三种不同的方法。第一种在有字节反转指令的系统上效率最高。
#define SWAPUC(a,b) do{unsigned char temp = (a); (a) = (b); (b) = temp;}while(0)
int reverse(int i)
{
unsigned int val = i;
if(sizeof(val) == 4)
val = ((val & 0xff) << 24) | ((val & 0xff00) << 8) | ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24);
if(sizeof(val) == 8)
val = ((val & 0x00000000000000ffULL) << 56) | ((val & 0xff00000000000000ULL) >> 56) |
((val & 0x000000000000ff00ULL) << 40) | ((val & 0x00ff000000000000ULL) >> 40) |
((val & 0x0000000000ff0000ULL) << 24) | ((val & 0x0000ff0000000000ULL) >> 24) |
((val & 0x00000000ff000000ULL) << 8) | ((val & 0x000000ff00000000ULL) >> 8);
return val;
}
int reverse1(int val)
{
union
{
unsigned i;
unsigned char uc[sizeof(val)];
}uni = {.i = val};
if(sizeof(val) == 8)
{
SWAPUC(uni.uc[7], uni.uc[0]);
SWAPUC(uni.uc[6], uni.uc[1]);
SWAPUC(uni.uc[5], uni.uc[2]);
SWAPUC(uni.uc[4], uni.uc[3]);
}
if(sizeof(val) == 4)
{
SWAPUC(uni.uc[3], uni.uc[0]);
SWAPUC(uni.uc[2], uni.uc[1]);
}
return uni.i;
}
int reverse2(int val)
{
unsigned char uc[sizeof(val)];
memcpy(uc, &val, sizeof(uc));
if(sizeof(val) == 8)
{
SWAPUC(uc[7], uc[0]);
SWAPUC(uc[6], uc[1]);
SWAPUC(uc[5], uc[2]);
SWAPUC(uc[4], uc[3]);
}
if(sizeof(val) == 4)
{
SWAPUC(uc[3], uc[0]);
SWAPUC(uc[2], uc[1]);
}
memcpy(&val, uc, sizeof(uc));
return val;
}
int main(void)
{
printf("%x\n", reverse2(0xaabbccdd));
}
生成的代码(x86):
reverse:
mov eax, edi
bswap eax
ret
reverse1:
mov eax, edi
xor edx, edx
mov ecx, edi
shr eax, 24
movzx esi, ch
sal ecx, 24
mov dl, al
mov eax, edi
sal esi, 16
shr eax, 16
mov dh, al
movzx eax, dx
or eax, esi
or eax, ecx
ret
reverse2:
mov eax, edi
xor edx, edx
mov ecx, edi
shr eax, 24
movzx esi, ch
sal ecx, 24
mov dl, al
mov eax, edi
sal esi, 16
shr eax, 16
mov dh, al
movzx eax, dx
or eax, esi
or eax, ecx
ret
.LC0:
.string "%x\n"
或者cortex M4(这个有字节交换指令)
reverse:
rev r0, r0
bx lr
reverse1:
mov r3, r0
lsrs r2, r3, #24
movs r0, #0
bfi r0, r2, #0, #8
ubfx r2, r3, #16, #8
bfi r0, r2, #8, #8
ubfx r2, r3, #8, #8
bfi r0, r2, #16, #8
bfi r0, r3, #24, #8
bx lr
reverse2:
mov r3, r0
lsrs r2, r3, #24
movs r0, #0
bfi r0, r2, #0, #8
ubfx r2, r3, #16, #8
bfi r0, r2, #8, #8
ubfx r2, r3, #8, #8
bfi r0, r2, #16, #8
bfi r0, r3, #24, #8
bx lr
.LC0:
因此获胜者是第一个仅使用按位算术的函数。
我已经用了很长时间了。
数据是指向要反转的值的指针
n 是要反转的字符数;通常 2、4、8 表示 short、int、long long。
但这在各种 architectures/OS
void SwapEndianN(char *data, unsigned short n) {
unsigned short k; char c;
for ( k=0 ; k < (n/2) ;k++ ) {
c = *(data+((n-1)-k));
*(data+((n-1)-k)) = *(data+k);
*(data+k) = c;
}
}