noobincoding - 1 year ago 83
C Question

Confusion in interpreting 32 bit integer in Big Endian and Little Endian Machines

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`
`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).

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.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download