for example i have uint64_t value = 42
and i would like to split it into 8 uint8_t
(8 bits), little endian. But I am unsure how to do the bit shifting. Help would be much appreciated.

- 27
- 6
-
3The endianess is irrelevant to the actual extracting of the bits. It only matters when you want to interpret the bits after extraction. To extract byte X just do `(value >> (X*8)) & 0xff` – kaylum Nov 14 '21 at 23:41
-
See e.g. [here](https://stackoverflow.com/q/61982660/589259) – Maarten Bodewes Nov 14 '21 at 23:43
4 Answers
If you want the individual bytes of a 64-bit value in little endian, then you can do the following:
In order to get the 1st byte, you simply apply the AND-bitmask 0xFF
. This will mask out all bits except for the 8 least-significant bits.
In order to get the 2nd byte, you shift right by 8 bits before applying the bit-mask.
In order to get the 3rd byte, you shift right by 16 bits before applying the bit-mask.
In order to get the 4th byte, you shift right by 24 bits before applying the bit-mask.
(...)
In order to get the 8th byte, you shift right by 56 bits before applying the bit-mask.
Here is the code for the value 42
(which is the example in the question):
#include <stdio.h>
#include <stdint.h>
int main( void )
{
uint64_t value = 42;
uint8_t bytes[8];
//extract the individual bytes
for ( int i = 0; i < 8; i++ )
{
bytes[i] = value >> (8 * i) & 0xFF;
}
//print the individual bytes
for ( int i = 0; i < 8; i++ )
{
printf( "%2d ", bytes[i] );
}
printf( "\n" );
}
Output:
42 0 0 0 0 0 0 0
If you replace the value 42
with the value 74579834759
in the program above, then you get the following output:
135 247 77 93 17 0 0 0

- 22,760
- 4
- 24
- 39
The following code works on both little-endian and big-endian platforms. On both types of platforms, it will produce the bytes in little-endian byte order.
uint64_t input = 42;
uint8_t values[8];
values[0] = input >> 0 & 0xFF;
values[1] = input >> 8 & 0xFF;
values[2] = input >> 16 & 0xFF;
values[3] = input >> 24 & 0xFF;
values[4] = input >> 32 & 0xFF;
values[5] = input >> 40 & 0xFF;
values[6] = input >> 48 & 0xFF;
values[7] = input >> 56 & 0xFF;
Note that the & 0xFF
is redundant here, but it makes the code more clear and it's useful if you want to do anything with the value other than immediately assign it to a uint8_t
variable.

- 22,760
- 4
- 24
- 39

- 84,103
- 24
- 152
- 189
-
`"This works regardless of the endianness:"` -- I disagree with this statement. If it were big-endian, then the bytes must be reversed: Either the left-hand side of the `=` operator would have to be reversed, so that you start with `values[7]` instead of `values[0]`, or the right-hand side of the `=` operator would have to be reversed, so that you start with `input >> 56 & 0xFF;` instead of `input >> 0 & 0xFF;`. – Andreas Wenzel Nov 15 '21 at 00:11
-
The OP didn't specify how the answer should look so we kinda just have to guess. I chose to put all the results into an array, but you could do other stuff with them. There is no rule that says the array has to match the bytes in original `uint64_t`, and in fact if people want that, then they should just access the `uint64_t` through a pointer of type `uint8_t *` that points at it. – David Grayson Nov 15 '21 at 00:45
-
To clarify what I meant: the 8 bytes this code produces depend only on the numeric value of the `uint64_t`, and not on the endianness of the machine the code is running on. – David Grayson Nov 15 '21 at 00:51
-
Ah, it seems that I did indeed misunderstand your answer. OP had asked for little-endian byte order and I interpreted your statement as claiming that endianness was irrelevant, as the solution would be the same if OP had asked for big-endian byte order. Now I understand that you did not intend to make this claim, but merely intended to state that your code does not rely on implementation-specific behavior regarding the endiannness, i.e. that your code will work on both little-endian and big-endian platforms. – Andreas Wenzel Nov 15 '21 at 01:50
-
I have added a clarification to your answer, to prevent this type of misunderstanding. – Andreas Wenzel Nov 15 '21 at 01:57
-
This could be made a little less repetitive with a `for` loop running `values[i] = input >> (i*8) & 0xFF;` I appreciate that writing out each byte makes it easier to understand, though. – tjcaul Nov 15 '21 at 07:59
Macro extracts b
th byte form the u
integer
#define EXTRACT(u,b) ((u) >> (8 * (b)))
int foo(uint64_t x)
{
uint8_t b[8] = {
EXTRACT(x,0),
EXTRACT(x,1),
EXTRACT(x,2),
EXTRACT(x,3),
EXTRACT(x,4),
EXTRACT(x,5),
EXTRACT(x,6),
EXTRACT(x,7),
};
}
If the platform is little endian you can also use memcpy
void foo(uint64_t x)
{
uint8_t b[8];
memcpy(b, &x, sizeof(b));
}

- 60,014
- 4
- 34
- 74
Here's a pointer approach to retrieve byte data from u64 data I usually use. Just share with you. But in this way, the user has to take care of the order.
#include <stdio.h>
#include <stdint.h>
void main(void)
{
int i;
uint64_t v = 0x123456789abcdef0;
uint8_t* ptrb;
ptrb = (uint8_t*)&v;
for (i = 0; i < 8; i++)
{
printf("%2x ", ptrb[i]);
}
printf("\n");
}
Below is the output with my sample code,
$ ./foo
f0 de bc 9a 78 56 34 12

- 49,934
- 160
- 51
- 83

- 48
- 7