如何反转字节顺序?

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;
  }
}