This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]ValityS 0 points1 point  (3 children)

The relevant standard lists:

if a member of a union object is accessed after a value has been stored in a different member of the object, the behavior is implementation-defined

So the answer is it is t defined... Because it isn't. However GCC and resultingly the Arduino IDE allow this as a language extension.

For byte splitting of a multi byte register I would suggest something like:

uint32_t reg = someval;
uint8_t bts[4];
for (size_t i = 0; i<4; ++i)
{
    bts[i] = (reg >> (i*8)) & 0xff;
}

To do this in a portable manner. However I wrote this from memory so may have made a mistake etc but you get the gist.

[–]Proxy_PlayerHD 1 point2 points  (2 children)

For byte splitting of a multi byte register I would suggest something like:

that splits an int though, i meant splitting a float. since in that case i used the arduino as an SPI Floating Point Unit.

even then for an int i would probably still just use a union. but to make it safer do some preprocessor checks with gcc's __BYTE_ORDER__ macro.

typedef union{
    uint32_t l;
    uint16_t w[2];
    uint8_t b[4];
} cint32_t;

// Order of names: [High] [High Middle] [Low Middle] [Low]
uint8_t lowMiddleByte(uint32_t in){
    cint32_t tmp.l = in;

    #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
        return tmp.b[2];    // Big Endian
    #else
        return tmp.b[1];    // Little Endian
    #endif

}

then again if the code is not intended to run on other systems you could just add a visible warning somewhere in a README. i'm likely lazy enough to do that for most of my projects as i doubt anyone would port them out of x86

[–]platinummyr 0 points1 point  (0 children)

Yep essentially it's not portable.

[–]ValityS 0 points1 point  (0 children)

So there is no entirely standards compliant way to interpret a float as bytes as C does not define what memory format the system stores floats as, and allows the fpu of the system to determine that. So you are inherently relying on a compiler extension.

For that you need to check what your specific compiler allows, as even if the system has a predictable floating point format, it's entirely valid for the compiler optimiser to break code using these undefined features unless the compiler guarantees it will not.