Reputation: 3
I am in process of rewriting code from Big Endian Machine to Little Endian machine.
Let's say there is a variable called a
, which is a 32 bit integer which holds current timestamp(user request's current timestamp).
In Big Endian machine, right now the code is this way:
uint32 a = current_timestamp_of_user_request;
uint8 arr[3] = {0};
arr[0] = ((a >> (8 * 2)) & 0x000000FF);
arr[1] = ((a >> (8 * 1)) & 0x000000FF);
arr[2] = ((a >> (8 * 0)) & 0x000000FF);
Now, when I am writing the same logic for little endian machine, can I use the same code(method a), or should I convert the code this way(let's call this method b)?
uint32 a = current_timestamp_of_user_request;
uint32 b = htonl(a);
uint8 arr[3] = {0};
arr[0] = ((b >> (8 * 2)) & 0x000000FF);
arr[1] = ((b >> (8 * 1)) & 0x000000FF);
arr[2] = ((b >> (8 * 0)) & 0x000000FF);
I wrote this program to verify:
#include<stdio.h>
#include<stdlib.h>
void main() {
long int a = 3265973637;
long int b = 0;
int arr[3] = {0,0,0};
arr[0] = ((a >> (8 * 2)) & 0x000000FF);
arr[1] = ((a >> (8 * 1)) & 0x000000FF);
arr[2] = ((a >> (8 * 0)) & 0x000000FF);
printf("arr[0] = %d\t arr[1] = %d\t arr[2] = %d\n", arr[0], arr[1], arr[2]);
b = htonl(a);
arr[0] = ((b >> (8 * 2)) & 0x000000FF);
arr[1] = ((b >> (8 * 1)) & 0x000000FF);
arr[2] = ((b >> (8 * 0)) & 0x000000FF);
printf("After htonl:\n");
printf("arr[0] = %d\t arr[1] = %d\t arr[2] = %d\n", arr[0], arr[1], arr[2]);
}
Results:
Result with little endian machine:
bgl-srtg-lnx11: /scratch/nnandiga/test>./x86
arr[0] = 170 arr[1] = 205 arr[2] = 133
After htonl:
arr[0] = 205 arr[1] = 170 arr[2] = 194
Result with big endian machine:
arr[0] = 170 arr[1] = 205 arr[2] = 133
After htonl:
arr[0] = 170 arr[1] = 205 arr[2] = 133
Looks like without conversion to big endian order, the same logic(without htonl()
) gives exact results in filling the array arr
. Now, can you please answer should I use htonl()
or not if I want the array to be the same in both little endian and big endian machines(little endian result should be exact as big endian result).
Upvotes: 1
Views: 1152
Reputation: 224387
Your code as originally written will do what you want on both big endian and little endian machines.
If for example the value of a
is 0x00123456
, then 0x12
goes in arr[0]
, 0x34
goes in arr[1]
, and 0x56
goes in arr[2]
. This occurs regardless of what the endianness of the machine is.
When you use the >>
and &
operators, they operate on the value of the expression in question, not the representation of that value.
When you call htonl
, you change the value to match a particular representation. So on a little endian machine htonl(0x00123456)
will result in the value 0x56341200
. Then when you operate on that value you get different results.
Where endianness matters is when the representation of a number using multiple bytes is read or written as bytes, i.e. to disk, over a network, or to/from a byte buffer.
For example, if you do this:
uint32_t a = 0x12345678;
...
write(fd, &a, sizeof(a));
Then the four bytes that a
consists of are written to the file descriptor (be it a file or a socket) one at a time. A big endian machine will write 0x12
, 0x34
, 0x56
, 0x78
in that order while a little endian machine will write 0x78
, 0x56
, 0x34
, 0x12
.
If you want the bytes to be written in a consistent order then you would first call a = htonl(a)
before calling write
. Then the bytes will always be written as 0x12
, 0x34
, 0x56
, 0x78
.
Because your code operates on the value and not the individual bytes of the value, you don't need to worry about endianness.
Upvotes: 2
Reputation: 781731
You should use htonl()
. On a big-endian machine this does nothing, it just returns the original value. On a little-endian machine it swaps the bytes appropriately. So by using this, you don't have to concern yourself with the endian-ness of the machine, you can use the same code after calling it.
Upvotes: 0