Portable way of splitting n-byte integer into single bytes












4















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.










share|improve this question




















  • 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
















4















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.










share|improve this question




















  • 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














4












4








4








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.










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 like union { uint32_t u32; uint8_t u8[4]; } t; t.u32 = value;

    – Giovanni Cerretani
    Jan 19 at 14:56














  • 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








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












1 Answer
1






active

oldest

votes


















7














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.






share|improve this answer





















  • 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











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
});


}
});














draft saved

draft discarded


















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









7














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.






share|improve this answer





















  • 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
















7














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.






share|improve this answer





















  • 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














7












7








7







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.






share|improve this answer















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.







share|improve this answer














share|improve this answer



share|improve this answer








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














  • 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


















draft saved

draft discarded




















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

Liquibase includeAll doesn't find base path

How to use setInterval in EJS file?

Petrus Granier-Deferre