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++);
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 |
+----------+ | +---+---+---+---+
| ^
+------+
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With