Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reverse endianness?

Tags:

c

endianness

Can someone help me understand this code?

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

I can't understand this part of code:

destination = ((char *) &resultat) + sizeof(int);
for (i = 0; i < sizeof(int); i++)
    *(--destination) = *(source++);

2 Answers

The following causes destination to point to the byte that follows resultat (as long as resultat is an int):

destination = ((char *) &resultat) + sizeof(int);

It could also have been written as follows:

destination = (char *)(&resultat + 1);

The following is just a simple memory copy loop:

for (i = 0; i < sizeof(int); i++)
        *(--destination) = *(source++);

It's equivalent to the following:

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

Program flow (assuming 32-bit int and 8-bit char)

After setup:

source               value
+----------+         +---+---+---+---+
|        -------+    | a | b | c | d |
+----------+    |    +---+---+---+---+
                |      ^
                +------+

destination          resultat 
+----------+         +---+---+---+---+
|        -------+    | 0 | 0 | 0 | 0 |
+----------+    |    +---+---+---+---+
                |                      ^
                +----------------------+

After one pass of the loop:

source               value
+----------+         +---+---+---+---+
|        -------+    | a | b | c | d |
+----------+    |    +---+---+---+---+
                |          ^
                +----------+

destination          resultat 
+----------+         +---+---+---+---+
|        -------+    | 0 | 0 | 0 | a |
+----------+    |    +---+---+---+---+
                |                  ^
                +------------------+

When it's done:

source               value
+----------+         +---+---+---+---+
|        -------+    | a | b | c | d |
+----------+    |    +---+---+---+---+
                |                      ^
                +----------------------+

destination          resultat 
+----------+         +---+---+---+---+
|        -------+    | d | c | b | a |
+----------+    |    +---+---+---+---+
                |      ^
                +------+
like image 143
ikegami Avatar answered Jan 23 '26 11:01

ikegami


Three different approaches. The first one is most efficient on the systems having byte reversing instructions.

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

The generated code (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"

Or cortex M4 (this one has byte swapping instruction)

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:

So the winner is the first function using only the bitwise arithmetics.

like image 44
0___________ Avatar answered Jan 23 '26 13:01

0___________