Portable way of splitting n-byte integer into single bytes
The problem is simple:
Take an 32-bit or 64-bit integer and split it up to send over an (usually)1-byte interface like uart, spi or i2c.
To do this I can easily use bit masking and shifting to get what I want. However, I want this to be portable that will work on big and little endian, but also make it work for platforms that don't discard bits but rotate through carry(masking gets rid of excess bits right?).
Example code:
uint32_t value;
uint8_t buffer[4];
buffer[0] = (value >> 24) & 0xFF;
buffer[1] = (value >> 16) & 0xFF;
buffer[2] = (value >> 8) & 0xFF;
buffer[3] = value & 0xFF;
I want to guarantee this works on any platform that supports 32 bit integers or more. I don't know if this is correct.
c bit-manipulation portability
|
show 2 more comments
The problem is simple:
Take an 32-bit or 64-bit integer and split it up to send over an (usually)1-byte interface like uart, spi or i2c.
To do this I can easily use bit masking and shifting to get what I want. However, I want this to be portable that will work on big and little endian, but also make it work for platforms that don't discard bits but rotate through carry(masking gets rid of excess bits right?).
Example code:
uint32_t value;
uint8_t buffer[4];
buffer[0] = (value >> 24) & 0xFF;
buffer[1] = (value >> 16) & 0xFF;
buffer[2] = (value >> 8) & 0xFF;
buffer[3] = value & 0xFF;
I want to guarantee this works on any platform that supports 32 bit integers or more. I don't know if this is correct.
c bit-manipulation portability
7
Shifting and masking is endian-proof.
– Weather Vane
Jan 18 at 14:21
Code is good and portable to modern machines. "make it work for platforms that don't discard bits but rather roll over to the other side as if it's a circular buffer" is unclear. Please explain more on that concern.
– chux
Jan 18 at 14:23
The>>
operator is always a shift, never a rotate (i.e. it always discards the rightmost bits).
– interjay
Jan 18 at 14:26
It is not the machine code that determines how the C code behaves, but the other way around. Unsigned shifts in C are guaranteed to behave as logical shifts, regardless of what instructions the CPU support. The resulting machine code might be a ROR instruction but carry is then discarded. The only exception being signed right-shifts on negative numbers, where C doesn't specify what will happen - the compiler is then free to either use logical shift or arithmetic shift.
– Lundin
Jan 18 at 14:35
You may also try with unions, using something likeunion { uint32_t u32; uint8_t u8[4]; } t; t.u32 = value;
– Giovanni Cerretani
Jan 19 at 14:56
|
show 2 more comments
The problem is simple:
Take an 32-bit or 64-bit integer and split it up to send over an (usually)1-byte interface like uart, spi or i2c.
To do this I can easily use bit masking and shifting to get what I want. However, I want this to be portable that will work on big and little endian, but also make it work for platforms that don't discard bits but rotate through carry(masking gets rid of excess bits right?).
Example code:
uint32_t value;
uint8_t buffer[4];
buffer[0] = (value >> 24) & 0xFF;
buffer[1] = (value >> 16) & 0xFF;
buffer[2] = (value >> 8) & 0xFF;
buffer[3] = value & 0xFF;
I want to guarantee this works on any platform that supports 32 bit integers or more. I don't know if this is correct.
c bit-manipulation portability
The problem is simple:
Take an 32-bit or 64-bit integer and split it up to send over an (usually)1-byte interface like uart, spi or i2c.
To do this I can easily use bit masking and shifting to get what I want. However, I want this to be portable that will work on big and little endian, but also make it work for platforms that don't discard bits but rotate through carry(masking gets rid of excess bits right?).
Example code:
uint32_t value;
uint8_t buffer[4];
buffer[0] = (value >> 24) & 0xFF;
buffer[1] = (value >> 16) & 0xFF;
buffer[2] = (value >> 8) & 0xFF;
buffer[3] = value & 0xFF;
I want to guarantee this works on any platform that supports 32 bit integers or more. I don't know if this is correct.
c bit-manipulation portability
c bit-manipulation portability
edited Jan 18 at 14:26
Tryphon
asked Jan 18 at 14:19
TryphonTryphon
556
556
7
Shifting and masking is endian-proof.
– Weather Vane
Jan 18 at 14:21
Code is good and portable to modern machines. "make it work for platforms that don't discard bits but rather roll over to the other side as if it's a circular buffer" is unclear. Please explain more on that concern.
– chux
Jan 18 at 14:23
The>>
operator is always a shift, never a rotate (i.e. it always discards the rightmost bits).
– interjay
Jan 18 at 14:26
It is not the machine code that determines how the C code behaves, but the other way around. Unsigned shifts in C are guaranteed to behave as logical shifts, regardless of what instructions the CPU support. The resulting machine code might be a ROR instruction but carry is then discarded. The only exception being signed right-shifts on negative numbers, where C doesn't specify what will happen - the compiler is then free to either use logical shift or arithmetic shift.
– Lundin
Jan 18 at 14:35
You may also try with unions, using something likeunion { uint32_t u32; uint8_t u8[4]; } t; t.u32 = value;
– Giovanni Cerretani
Jan 19 at 14:56
|
show 2 more comments
7
Shifting and masking is endian-proof.
– Weather Vane
Jan 18 at 14:21
Code is good and portable to modern machines. "make it work for platforms that don't discard bits but rather roll over to the other side as if it's a circular buffer" is unclear. Please explain more on that concern.
– chux
Jan 18 at 14:23
The>>
operator is always a shift, never a rotate (i.e. it always discards the rightmost bits).
– interjay
Jan 18 at 14:26
It is not the machine code that determines how the C code behaves, but the other way around. Unsigned shifts in C are guaranteed to behave as logical shifts, regardless of what instructions the CPU support. The resulting machine code might be a ROR instruction but carry is then discarded. The only exception being signed right-shifts on negative numbers, where C doesn't specify what will happen - the compiler is then free to either use logical shift or arithmetic shift.
– Lundin
Jan 18 at 14:35
You may also try with unions, using something likeunion { uint32_t u32; uint8_t u8[4]; } t; t.u32 = value;
– Giovanni Cerretani
Jan 19 at 14:56
7
7
Shifting and masking is endian-proof.
– Weather Vane
Jan 18 at 14:21
Shifting and masking is endian-proof.
– Weather Vane
Jan 18 at 14:21
Code is good and portable to modern machines. "make it work for platforms that don't discard bits but rather roll over to the other side as if it's a circular buffer" is unclear. Please explain more on that concern.
– chux
Jan 18 at 14:23
Code is good and portable to modern machines. "make it work for platforms that don't discard bits but rather roll over to the other side as if it's a circular buffer" is unclear. Please explain more on that concern.
– chux
Jan 18 at 14:23
The
>>
operator is always a shift, never a rotate (i.e. it always discards the rightmost bits).– interjay
Jan 18 at 14:26
The
>>
operator is always a shift, never a rotate (i.e. it always discards the rightmost bits).– interjay
Jan 18 at 14:26
It is not the machine code that determines how the C code behaves, but the other way around. Unsigned shifts in C are guaranteed to behave as logical shifts, regardless of what instructions the CPU support. The resulting machine code might be a ROR instruction but carry is then discarded. The only exception being signed right-shifts on negative numbers, where C doesn't specify what will happen - the compiler is then free to either use logical shift or arithmetic shift.
– Lundin
Jan 18 at 14:35
It is not the machine code that determines how the C code behaves, but the other way around. Unsigned shifts in C are guaranteed to behave as logical shifts, regardless of what instructions the CPU support. The resulting machine code might be a ROR instruction but carry is then discarded. The only exception being signed right-shifts on negative numbers, where C doesn't specify what will happen - the compiler is then free to either use logical shift or arithmetic shift.
– Lundin
Jan 18 at 14:35
You may also try with unions, using something like
union { uint32_t u32; uint8_t u8[4]; } t; t.u32 = value;
– Giovanni Cerretani
Jan 19 at 14:56
You may also try with unions, using something like
union { uint32_t u32; uint8_t u8[4]; } t; t.u32 = value;
– Giovanni Cerretani
Jan 19 at 14:56
|
show 2 more comments
1 Answer
1
active
oldest
votes
The code you presented is the most portable way of doing it. You convert a single unsigned integer value with 32 bits width into an array of unsigned integer values of exactly 8 bits width. The resulting bytes in the buffer
array are in big endian order.
The masking is not needed. From C11 6.5.7p5:
The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has
a signed type and a nonnegative value, the value of the result is the integral part of the quotient of
E1 / 2^E2.
and casting to an integer with 8 bits width is (to the value) equal to masking 8 bits. So (result >> 24) & 0xff
is equal to (uint8_t)(result >> 24)
(to the value). As you assign to uint8_t
variable the masking is not needed. Anyway I would safely assume it will be optimized out by a sane compiler.
I can recommend to take a look at one implementation that I remembered, that I guess has implemented in a really safe manner all the possible variants of splitting and composing fixed-width integers up to 64 bits from bytes and back, that is at gpsd bits.h.
1
The masking is often needed to silence compiler/static analyser warnings. For example a MISRA-C checker will even require that you use(uint8_t)(value >> 24)
with an explicit conversion through cast.
– Lundin
Jan 18 at 14:39
MISRA should be considered as a separate distinct language :).
– P__J__
Jan 18 at 15:22
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54255885%2fportable-way-of-splitting-n-byte-integer-into-single-bytes%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
The code you presented is the most portable way of doing it. You convert a single unsigned integer value with 32 bits width into an array of unsigned integer values of exactly 8 bits width. The resulting bytes in the buffer
array are in big endian order.
The masking is not needed. From C11 6.5.7p5:
The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has
a signed type and a nonnegative value, the value of the result is the integral part of the quotient of
E1 / 2^E2.
and casting to an integer with 8 bits width is (to the value) equal to masking 8 bits. So (result >> 24) & 0xff
is equal to (uint8_t)(result >> 24)
(to the value). As you assign to uint8_t
variable the masking is not needed. Anyway I would safely assume it will be optimized out by a sane compiler.
I can recommend to take a look at one implementation that I remembered, that I guess has implemented in a really safe manner all the possible variants of splitting and composing fixed-width integers up to 64 bits from bytes and back, that is at gpsd bits.h.
1
The masking is often needed to silence compiler/static analyser warnings. For example a MISRA-C checker will even require that you use(uint8_t)(value >> 24)
with an explicit conversion through cast.
– Lundin
Jan 18 at 14:39
MISRA should be considered as a separate distinct language :).
– P__J__
Jan 18 at 15:22
add a comment |
The code you presented is the most portable way of doing it. You convert a single unsigned integer value with 32 bits width into an array of unsigned integer values of exactly 8 bits width. The resulting bytes in the buffer
array are in big endian order.
The masking is not needed. From C11 6.5.7p5:
The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has
a signed type and a nonnegative value, the value of the result is the integral part of the quotient of
E1 / 2^E2.
and casting to an integer with 8 bits width is (to the value) equal to masking 8 bits. So (result >> 24) & 0xff
is equal to (uint8_t)(result >> 24)
(to the value). As you assign to uint8_t
variable the masking is not needed. Anyway I would safely assume it will be optimized out by a sane compiler.
I can recommend to take a look at one implementation that I remembered, that I guess has implemented in a really safe manner all the possible variants of splitting and composing fixed-width integers up to 64 bits from bytes and back, that is at gpsd bits.h.
1
The masking is often needed to silence compiler/static analyser warnings. For example a MISRA-C checker will even require that you use(uint8_t)(value >> 24)
with an explicit conversion through cast.
– Lundin
Jan 18 at 14:39
MISRA should be considered as a separate distinct language :).
– P__J__
Jan 18 at 15:22
add a comment |
The code you presented is the most portable way of doing it. You convert a single unsigned integer value with 32 bits width into an array of unsigned integer values of exactly 8 bits width. The resulting bytes in the buffer
array are in big endian order.
The masking is not needed. From C11 6.5.7p5:
The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has
a signed type and a nonnegative value, the value of the result is the integral part of the quotient of
E1 / 2^E2.
and casting to an integer with 8 bits width is (to the value) equal to masking 8 bits. So (result >> 24) & 0xff
is equal to (uint8_t)(result >> 24)
(to the value). As you assign to uint8_t
variable the masking is not needed. Anyway I would safely assume it will be optimized out by a sane compiler.
I can recommend to take a look at one implementation that I remembered, that I guess has implemented in a really safe manner all the possible variants of splitting and composing fixed-width integers up to 64 bits from bytes and back, that is at gpsd bits.h.
The code you presented is the most portable way of doing it. You convert a single unsigned integer value with 32 bits width into an array of unsigned integer values of exactly 8 bits width. The resulting bytes in the buffer
array are in big endian order.
The masking is not needed. From C11 6.5.7p5:
The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has
a signed type and a nonnegative value, the value of the result is the integral part of the quotient of
E1 / 2^E2.
and casting to an integer with 8 bits width is (to the value) equal to masking 8 bits. So (result >> 24) & 0xff
is equal to (uint8_t)(result >> 24)
(to the value). As you assign to uint8_t
variable the masking is not needed. Anyway I would safely assume it will be optimized out by a sane compiler.
I can recommend to take a look at one implementation that I remembered, that I guess has implemented in a really safe manner all the possible variants of splitting and composing fixed-width integers up to 64 bits from bytes and back, that is at gpsd bits.h.
edited Jan 18 at 14:48
answered Jan 18 at 14:29
Kamil CukKamil Cuk
9,8911527
9,8911527
1
The masking is often needed to silence compiler/static analyser warnings. For example a MISRA-C checker will even require that you use(uint8_t)(value >> 24)
with an explicit conversion through cast.
– Lundin
Jan 18 at 14:39
MISRA should be considered as a separate distinct language :).
– P__J__
Jan 18 at 15:22
add a comment |
1
The masking is often needed to silence compiler/static analyser warnings. For example a MISRA-C checker will even require that you use(uint8_t)(value >> 24)
with an explicit conversion through cast.
– Lundin
Jan 18 at 14:39
MISRA should be considered as a separate distinct language :).
– P__J__
Jan 18 at 15:22
1
1
The masking is often needed to silence compiler/static analyser warnings. For example a MISRA-C checker will even require that you use
(uint8_t)(value >> 24)
with an explicit conversion through cast.– Lundin
Jan 18 at 14:39
The masking is often needed to silence compiler/static analyser warnings. For example a MISRA-C checker will even require that you use
(uint8_t)(value >> 24)
with an explicit conversion through cast.– Lundin
Jan 18 at 14:39
MISRA should be considered as a separate distinct language :).
– P__J__
Jan 18 at 15:22
MISRA should be considered as a separate distinct language :).
– P__J__
Jan 18 at 15:22
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54255885%2fportable-way-of-splitting-n-byte-integer-into-single-bytes%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
7
Shifting and masking is endian-proof.
– Weather Vane
Jan 18 at 14:21
Code is good and portable to modern machines. "make it work for platforms that don't discard bits but rather roll over to the other side as if it's a circular buffer" is unclear. Please explain more on that concern.
– chux
Jan 18 at 14:23
The
>>
operator is always a shift, never a rotate (i.e. it always discards the rightmost bits).– interjay
Jan 18 at 14:26
It is not the machine code that determines how the C code behaves, but the other way around. Unsigned shifts in C are guaranteed to behave as logical shifts, regardless of what instructions the CPU support. The resulting machine code might be a ROR instruction but carry is then discarded. The only exception being signed right-shifts on negative numbers, where C doesn't specify what will happen - the compiler is then free to either use logical shift or arithmetic shift.
– Lundin
Jan 18 at 14:35
You may also try with unions, using something like
union { uint32_t u32; uint8_t u8[4]; } t; t.u32 = value;
– Giovanni Cerretani
Jan 19 at 14:56