Strict aliasing rule uint8_t buffer to structure












6















Consider I have a typedef with bit fields as below.



typedef struct VIN_oCAN01_3abd61be
{
uint64_t var1:24;
uint64_t var2:4;
uint64_t var3:4
}__attribute__((packed))Message;


And I receive uint8_t buffer as below.



uint8_t buffer[4] = {0x1,0x2,0x3,0x14};




Currently in my production program my team is suggesting below approach.



Message *ptrMsg = (Message *)buffer;


That is, assigning uint8_t buffer to Message type pointer.
I had suggested that proposed approach does not follow strict aliasing rule and instead we should do as below.



Message msg;
memcpy(&msg,buffer, sizeof(msg));



Note there is no option of copying the buffer to structure
manually(member by member) as structure is very big.




Is my understanding is correct? If so can you please provide the standard doc which I can use to prove my point.










share|improve this question























  • Besides the strict aliasing violation problem, beware of indianness. Filling a uint from a char with memcpy makes your code completely non portable.

    – Alain Merigot
    4 hours ago











  • @AlainMerigot Good catch!, We are handling endianness just before the memcpy or pointer assignment, it is just that I have not shown here.

    – kiran Biradar
    4 hours ago













  • I think that strict aliasing is a compiler thing and usually it has a flag if it may or may not assume strict aliasing for different optimization levels.

    – Alex Lop.
    4 hours ago






  • 1





    @user694733 I have bit fields defined.

    – kiran Biradar
    4 hours ago






  • 1





    Your bitfields add up to 32 bits, in a uint64_t. You have no idea where in those 64 bits those bitfields actually are. Per 6.7.2.1p11: "whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified." Bitfields are just plain bad news for portability and maintainability.

    – Andrew Henle
    4 hours ago


















6















Consider I have a typedef with bit fields as below.



typedef struct VIN_oCAN01_3abd61be
{
uint64_t var1:24;
uint64_t var2:4;
uint64_t var3:4
}__attribute__((packed))Message;


And I receive uint8_t buffer as below.



uint8_t buffer[4] = {0x1,0x2,0x3,0x14};




Currently in my production program my team is suggesting below approach.



Message *ptrMsg = (Message *)buffer;


That is, assigning uint8_t buffer to Message type pointer.
I had suggested that proposed approach does not follow strict aliasing rule and instead we should do as below.



Message msg;
memcpy(&msg,buffer, sizeof(msg));



Note there is no option of copying the buffer to structure
manually(member by member) as structure is very big.




Is my understanding is correct? If so can you please provide the standard doc which I can use to prove my point.










share|improve this question























  • Besides the strict aliasing violation problem, beware of indianness. Filling a uint from a char with memcpy makes your code completely non portable.

    – Alain Merigot
    4 hours ago











  • @AlainMerigot Good catch!, We are handling endianness just before the memcpy or pointer assignment, it is just that I have not shown here.

    – kiran Biradar
    4 hours ago













  • I think that strict aliasing is a compiler thing and usually it has a flag if it may or may not assume strict aliasing for different optimization levels.

    – Alex Lop.
    4 hours ago






  • 1





    @user694733 I have bit fields defined.

    – kiran Biradar
    4 hours ago






  • 1





    Your bitfields add up to 32 bits, in a uint64_t. You have no idea where in those 64 bits those bitfields actually are. Per 6.7.2.1p11: "whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified." Bitfields are just plain bad news for portability and maintainability.

    – Andrew Henle
    4 hours ago
















6












6








6








Consider I have a typedef with bit fields as below.



typedef struct VIN_oCAN01_3abd61be
{
uint64_t var1:24;
uint64_t var2:4;
uint64_t var3:4
}__attribute__((packed))Message;


And I receive uint8_t buffer as below.



uint8_t buffer[4] = {0x1,0x2,0x3,0x14};




Currently in my production program my team is suggesting below approach.



Message *ptrMsg = (Message *)buffer;


That is, assigning uint8_t buffer to Message type pointer.
I had suggested that proposed approach does not follow strict aliasing rule and instead we should do as below.



Message msg;
memcpy(&msg,buffer, sizeof(msg));



Note there is no option of copying the buffer to structure
manually(member by member) as structure is very big.




Is my understanding is correct? If so can you please provide the standard doc which I can use to prove my point.










share|improve this question














Consider I have a typedef with bit fields as below.



typedef struct VIN_oCAN01_3abd61be
{
uint64_t var1:24;
uint64_t var2:4;
uint64_t var3:4
}__attribute__((packed))Message;


And I receive uint8_t buffer as below.



uint8_t buffer[4] = {0x1,0x2,0x3,0x14};




Currently in my production program my team is suggesting below approach.



Message *ptrMsg = (Message *)buffer;


That is, assigning uint8_t buffer to Message type pointer.
I had suggested that proposed approach does not follow strict aliasing rule and instead we should do as below.



Message msg;
memcpy(&msg,buffer, sizeof(msg));



Note there is no option of copying the buffer to structure
manually(member by member) as structure is very big.




Is my understanding is correct? If so can you please provide the standard doc which I can use to prove my point.







c






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked 5 hours ago









kiran Biradarkiran Biradar

4,9142926




4,9142926













  • Besides the strict aliasing violation problem, beware of indianness. Filling a uint from a char with memcpy makes your code completely non portable.

    – Alain Merigot
    4 hours ago











  • @AlainMerigot Good catch!, We are handling endianness just before the memcpy or pointer assignment, it is just that I have not shown here.

    – kiran Biradar
    4 hours ago













  • I think that strict aliasing is a compiler thing and usually it has a flag if it may or may not assume strict aliasing for different optimization levels.

    – Alex Lop.
    4 hours ago






  • 1





    @user694733 I have bit fields defined.

    – kiran Biradar
    4 hours ago






  • 1





    Your bitfields add up to 32 bits, in a uint64_t. You have no idea where in those 64 bits those bitfields actually are. Per 6.7.2.1p11: "whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified." Bitfields are just plain bad news for portability and maintainability.

    – Andrew Henle
    4 hours ago





















  • Besides the strict aliasing violation problem, beware of indianness. Filling a uint from a char with memcpy makes your code completely non portable.

    – Alain Merigot
    4 hours ago











  • @AlainMerigot Good catch!, We are handling endianness just before the memcpy or pointer assignment, it is just that I have not shown here.

    – kiran Biradar
    4 hours ago













  • I think that strict aliasing is a compiler thing and usually it has a flag if it may or may not assume strict aliasing for different optimization levels.

    – Alex Lop.
    4 hours ago






  • 1





    @user694733 I have bit fields defined.

    – kiran Biradar
    4 hours ago






  • 1





    Your bitfields add up to 32 bits, in a uint64_t. You have no idea where in those 64 bits those bitfields actually are. Per 6.7.2.1p11: "whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified." Bitfields are just plain bad news for portability and maintainability.

    – Andrew Henle
    4 hours ago



















Besides the strict aliasing violation problem, beware of indianness. Filling a uint from a char with memcpy makes your code completely non portable.

– Alain Merigot
4 hours ago





Besides the strict aliasing violation problem, beware of indianness. Filling a uint from a char with memcpy makes your code completely non portable.

– Alain Merigot
4 hours ago













@AlainMerigot Good catch!, We are handling endianness just before the memcpy or pointer assignment, it is just that I have not shown here.

– kiran Biradar
4 hours ago







@AlainMerigot Good catch!, We are handling endianness just before the memcpy or pointer assignment, it is just that I have not shown here.

– kiran Biradar
4 hours ago















I think that strict aliasing is a compiler thing and usually it has a flag if it may or may not assume strict aliasing for different optimization levels.

– Alex Lop.
4 hours ago





I think that strict aliasing is a compiler thing and usually it has a flag if it may or may not assume strict aliasing for different optimization levels.

– Alex Lop.
4 hours ago




1




1





@user694733 I have bit fields defined.

– kiran Biradar
4 hours ago





@user694733 I have bit fields defined.

– kiran Biradar
4 hours ago




1




1





Your bitfields add up to 32 bits, in a uint64_t. You have no idea where in those 64 bits those bitfields actually are. Per 6.7.2.1p11: "whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified." Bitfields are just plain bad news for portability and maintainability.

– Andrew Henle
4 hours ago







Your bitfields add up to 32 bits, in a uint64_t. You have no idea where in those 64 bits those bitfields actually are. Per 6.7.2.1p11: "whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified." Bitfields are just plain bad news for portability and maintainability.

– Andrew Henle
4 hours ago














2 Answers
2






active

oldest

votes


















5















I had suggested that proposed approach does not follow strict aliasing rule




Correct. ptrMsg = (Message *)buffer means that you cannot access the data of ptrMsg without invoking undefined behavior.



You can prove your point with C17 6.5 §7 (cited here - What is the strict aliasing rule?). An lvalue expression such as ptrMsg->var1 = value does not access the stored value through a type compatible with the effective type of what's stored there, nor through any of the allowed expressions.



You can however go from Message to an array of uint8_t (assuming uint8_t is a character type) without violating strict aliasing.





The larger problem is however the precece of the bit-field in the first place, which is non-standard and non-portable. For example, you cannot know which part of the bit-field that is the MSB and LSB. You cannot know how the bits are aligned in the 64 bit type. Using a 64 bit type for a bit-field is a non-standard extension. It is endianess-dependent. And so on.





Assuming the 24 bits refer to bit 31 to 8 (we can't know by reading your code), then proper code without strict aliasing violations, bit-field madness and non-standard "struct padding killers" would look like this:



typedef union
{
uint32_t var;
uint8_t bytes[4];
} Message;


uint8_t buffer[4];
Message* ptrMsg = (Message*)buffer;
uint32_t var1 = (ptrMsg->var >> 8);
uint8_t var2 = (ptrMsg->var >> 4) & 0x0F;
uint8_t var3 = (ptrMsg->var) & 0x0F;


Message being "a union type that includes one of the aforementioned types among its
members". Meaning it contains a type compatible with uint8_t [4].



This code also contains no copying and the shifts will get translated to the relevant bit access in the machine code.






share|improve this answer

































    4














    You are right.



    C17 draft § 6.5:






    1. An object shall have its stored value accessed only by an lvalue expression that has one of the
      following types: 89)




      • a type compatible with the effective type of the object,


      • a qualified version of a type compatible with the effective type of the object,


      • a type that is the signed or unsigned type corresponding to the effective type of the object,


      • a type that is the signed or unsigned type corresponding to a qualified version of the effective
        type of the object,


      • an aggregate or union type that includes one of the aforementioned types among its members
        (including, recursively, a member of a subaggregate or contained union), or

      • a character type.






    In this case the object is of type uint8_t and type of the lvalue expression is Message. None of the exceptions above apply.



    Using memcpy over dereferences fixes this issue, or alternatively you can disable the strict aliasing in your compiler if you want to write in non-C language.



    But even after this the code has a lot of problems and is not portable: Bitfields are extremely poorly defined in standard and overall structures are very clumsy way to handle serialization. You should take the option of deserializing each member manually.






    share|improve this answer
























    • In all fairness, disabling strict aliasing is not a bad idea at all. In particularly or embedded systems design, which this appears to be. Strict aliasing/effective type is a broken part of the C language, specified by PC programmers who don't grasp the type punning often needed in embedded systems. In addition, GCC is the only compiler I know of which abuses strict aliasing to produce faster code that does not at all perform what the unaware programmer intended. But it does so efficiently! Better to always use gcc -fno-strict-aliasing.

      – Lundin
      4 hours ago











    • @Lundin But the flip side of that is programmers with no experience on systems where violating strict aliasing causes actual problems. Thus you get questions like this one, where a bunch of programmers with apparently no understanding at all regarding strict aliasing looks to have prompted someone who does understand the implications to post a question on Stackoverflow.

      – Andrew Henle
      4 hours ago











    • @AndrewHenle But the strict aliasing rule isn't really common knowledge. It takes a hardened C veteran/language nerd to know about it and understand it. Which in turn makes it a safety hazard and language flaw. Particularly since prior C99, no compiler did aggressive optimizations relying on it... and it took around 10 years for C99 to become industry standard. We didn't really see strict aliasing bugs in embedded systems until around 2009, when gcc started to become popular as ARM compiler. And so the non-nerds have to use MISRA-C to tell them "don't do this" without understanding why.

      – Lundin
      3 hours ago











    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%2f54237004%2fstrict-aliasing-rule-uint8-t-buffer-to-structure%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    5















    I had suggested that proposed approach does not follow strict aliasing rule




    Correct. ptrMsg = (Message *)buffer means that you cannot access the data of ptrMsg without invoking undefined behavior.



    You can prove your point with C17 6.5 §7 (cited here - What is the strict aliasing rule?). An lvalue expression such as ptrMsg->var1 = value does not access the stored value through a type compatible with the effective type of what's stored there, nor through any of the allowed expressions.



    You can however go from Message to an array of uint8_t (assuming uint8_t is a character type) without violating strict aliasing.





    The larger problem is however the precece of the bit-field in the first place, which is non-standard and non-portable. For example, you cannot know which part of the bit-field that is the MSB and LSB. You cannot know how the bits are aligned in the 64 bit type. Using a 64 bit type for a bit-field is a non-standard extension. It is endianess-dependent. And so on.





    Assuming the 24 bits refer to bit 31 to 8 (we can't know by reading your code), then proper code without strict aliasing violations, bit-field madness and non-standard "struct padding killers" would look like this:



    typedef union
    {
    uint32_t var;
    uint8_t bytes[4];
    } Message;


    uint8_t buffer[4];
    Message* ptrMsg = (Message*)buffer;
    uint32_t var1 = (ptrMsg->var >> 8);
    uint8_t var2 = (ptrMsg->var >> 4) & 0x0F;
    uint8_t var3 = (ptrMsg->var) & 0x0F;


    Message being "a union type that includes one of the aforementioned types among its
    members". Meaning it contains a type compatible with uint8_t [4].



    This code also contains no copying and the shifts will get translated to the relevant bit access in the machine code.






    share|improve this answer






























      5















      I had suggested that proposed approach does not follow strict aliasing rule




      Correct. ptrMsg = (Message *)buffer means that you cannot access the data of ptrMsg without invoking undefined behavior.



      You can prove your point with C17 6.5 §7 (cited here - What is the strict aliasing rule?). An lvalue expression such as ptrMsg->var1 = value does not access the stored value through a type compatible with the effective type of what's stored there, nor through any of the allowed expressions.



      You can however go from Message to an array of uint8_t (assuming uint8_t is a character type) without violating strict aliasing.





      The larger problem is however the precece of the bit-field in the first place, which is non-standard and non-portable. For example, you cannot know which part of the bit-field that is the MSB and LSB. You cannot know how the bits are aligned in the 64 bit type. Using a 64 bit type for a bit-field is a non-standard extension. It is endianess-dependent. And so on.





      Assuming the 24 bits refer to bit 31 to 8 (we can't know by reading your code), then proper code without strict aliasing violations, bit-field madness and non-standard "struct padding killers" would look like this:



      typedef union
      {
      uint32_t var;
      uint8_t bytes[4];
      } Message;


      uint8_t buffer[4];
      Message* ptrMsg = (Message*)buffer;
      uint32_t var1 = (ptrMsg->var >> 8);
      uint8_t var2 = (ptrMsg->var >> 4) & 0x0F;
      uint8_t var3 = (ptrMsg->var) & 0x0F;


      Message being "a union type that includes one of the aforementioned types among its
      members". Meaning it contains a type compatible with uint8_t [4].



      This code also contains no copying and the shifts will get translated to the relevant bit access in the machine code.






      share|improve this answer




























        5












        5








        5








        I had suggested that proposed approach does not follow strict aliasing rule




        Correct. ptrMsg = (Message *)buffer means that you cannot access the data of ptrMsg without invoking undefined behavior.



        You can prove your point with C17 6.5 §7 (cited here - What is the strict aliasing rule?). An lvalue expression such as ptrMsg->var1 = value does not access the stored value through a type compatible with the effective type of what's stored there, nor through any of the allowed expressions.



        You can however go from Message to an array of uint8_t (assuming uint8_t is a character type) without violating strict aliasing.





        The larger problem is however the precece of the bit-field in the first place, which is non-standard and non-portable. For example, you cannot know which part of the bit-field that is the MSB and LSB. You cannot know how the bits are aligned in the 64 bit type. Using a 64 bit type for a bit-field is a non-standard extension. It is endianess-dependent. And so on.





        Assuming the 24 bits refer to bit 31 to 8 (we can't know by reading your code), then proper code without strict aliasing violations, bit-field madness and non-standard "struct padding killers" would look like this:



        typedef union
        {
        uint32_t var;
        uint8_t bytes[4];
        } Message;


        uint8_t buffer[4];
        Message* ptrMsg = (Message*)buffer;
        uint32_t var1 = (ptrMsg->var >> 8);
        uint8_t var2 = (ptrMsg->var >> 4) & 0x0F;
        uint8_t var3 = (ptrMsg->var) & 0x0F;


        Message being "a union type that includes one of the aforementioned types among its
        members". Meaning it contains a type compatible with uint8_t [4].



        This code also contains no copying and the shifts will get translated to the relevant bit access in the machine code.






        share|improve this answer
















        I had suggested that proposed approach does not follow strict aliasing rule




        Correct. ptrMsg = (Message *)buffer means that you cannot access the data of ptrMsg without invoking undefined behavior.



        You can prove your point with C17 6.5 §7 (cited here - What is the strict aliasing rule?). An lvalue expression such as ptrMsg->var1 = value does not access the stored value through a type compatible with the effective type of what's stored there, nor through any of the allowed expressions.



        You can however go from Message to an array of uint8_t (assuming uint8_t is a character type) without violating strict aliasing.





        The larger problem is however the precece of the bit-field in the first place, which is non-standard and non-portable. For example, you cannot know which part of the bit-field that is the MSB and LSB. You cannot know how the bits are aligned in the 64 bit type. Using a 64 bit type for a bit-field is a non-standard extension. It is endianess-dependent. And so on.





        Assuming the 24 bits refer to bit 31 to 8 (we can't know by reading your code), then proper code without strict aliasing violations, bit-field madness and non-standard "struct padding killers" would look like this:



        typedef union
        {
        uint32_t var;
        uint8_t bytes[4];
        } Message;


        uint8_t buffer[4];
        Message* ptrMsg = (Message*)buffer;
        uint32_t var1 = (ptrMsg->var >> 8);
        uint8_t var2 = (ptrMsg->var >> 4) & 0x0F;
        uint8_t var3 = (ptrMsg->var) & 0x0F;


        Message being "a union type that includes one of the aforementioned types among its
        members". Meaning it contains a type compatible with uint8_t [4].



        This code also contains no copying and the shifts will get translated to the relevant bit access in the machine code.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 2 hours ago

























        answered 4 hours ago









        LundinLundin

        108k17158262




        108k17158262

























            4














            You are right.



            C17 draft § 6.5:






            1. An object shall have its stored value accessed only by an lvalue expression that has one of the
              following types: 89)




              • a type compatible with the effective type of the object,


              • a qualified version of a type compatible with the effective type of the object,


              • a type that is the signed or unsigned type corresponding to the effective type of the object,


              • a type that is the signed or unsigned type corresponding to a qualified version of the effective
                type of the object,


              • an aggregate or union type that includes one of the aforementioned types among its members
                (including, recursively, a member of a subaggregate or contained union), or

              • a character type.






            In this case the object is of type uint8_t and type of the lvalue expression is Message. None of the exceptions above apply.



            Using memcpy over dereferences fixes this issue, or alternatively you can disable the strict aliasing in your compiler if you want to write in non-C language.



            But even after this the code has a lot of problems and is not portable: Bitfields are extremely poorly defined in standard and overall structures are very clumsy way to handle serialization. You should take the option of deserializing each member manually.






            share|improve this answer
























            • In all fairness, disabling strict aliasing is not a bad idea at all. In particularly or embedded systems design, which this appears to be. Strict aliasing/effective type is a broken part of the C language, specified by PC programmers who don't grasp the type punning often needed in embedded systems. In addition, GCC is the only compiler I know of which abuses strict aliasing to produce faster code that does not at all perform what the unaware programmer intended. But it does so efficiently! Better to always use gcc -fno-strict-aliasing.

              – Lundin
              4 hours ago











            • @Lundin But the flip side of that is programmers with no experience on systems where violating strict aliasing causes actual problems. Thus you get questions like this one, where a bunch of programmers with apparently no understanding at all regarding strict aliasing looks to have prompted someone who does understand the implications to post a question on Stackoverflow.

              – Andrew Henle
              4 hours ago











            • @AndrewHenle But the strict aliasing rule isn't really common knowledge. It takes a hardened C veteran/language nerd to know about it and understand it. Which in turn makes it a safety hazard and language flaw. Particularly since prior C99, no compiler did aggressive optimizations relying on it... and it took around 10 years for C99 to become industry standard. We didn't really see strict aliasing bugs in embedded systems until around 2009, when gcc started to become popular as ARM compiler. And so the non-nerds have to use MISRA-C to tell them "don't do this" without understanding why.

              – Lundin
              3 hours ago
















            4














            You are right.



            C17 draft § 6.5:






            1. An object shall have its stored value accessed only by an lvalue expression that has one of the
              following types: 89)




              • a type compatible with the effective type of the object,


              • a qualified version of a type compatible with the effective type of the object,


              • a type that is the signed or unsigned type corresponding to the effective type of the object,


              • a type that is the signed or unsigned type corresponding to a qualified version of the effective
                type of the object,


              • an aggregate or union type that includes one of the aforementioned types among its members
                (including, recursively, a member of a subaggregate or contained union), or

              • a character type.






            In this case the object is of type uint8_t and type of the lvalue expression is Message. None of the exceptions above apply.



            Using memcpy over dereferences fixes this issue, or alternatively you can disable the strict aliasing in your compiler if you want to write in non-C language.



            But even after this the code has a lot of problems and is not portable: Bitfields are extremely poorly defined in standard and overall structures are very clumsy way to handle serialization. You should take the option of deserializing each member manually.






            share|improve this answer
























            • In all fairness, disabling strict aliasing is not a bad idea at all. In particularly or embedded systems design, which this appears to be. Strict aliasing/effective type is a broken part of the C language, specified by PC programmers who don't grasp the type punning often needed in embedded systems. In addition, GCC is the only compiler I know of which abuses strict aliasing to produce faster code that does not at all perform what the unaware programmer intended. But it does so efficiently! Better to always use gcc -fno-strict-aliasing.

              – Lundin
              4 hours ago











            • @Lundin But the flip side of that is programmers with no experience on systems where violating strict aliasing causes actual problems. Thus you get questions like this one, where a bunch of programmers with apparently no understanding at all regarding strict aliasing looks to have prompted someone who does understand the implications to post a question on Stackoverflow.

              – Andrew Henle
              4 hours ago











            • @AndrewHenle But the strict aliasing rule isn't really common knowledge. It takes a hardened C veteran/language nerd to know about it and understand it. Which in turn makes it a safety hazard and language flaw. Particularly since prior C99, no compiler did aggressive optimizations relying on it... and it took around 10 years for C99 to become industry standard. We didn't really see strict aliasing bugs in embedded systems until around 2009, when gcc started to become popular as ARM compiler. And so the non-nerds have to use MISRA-C to tell them "don't do this" without understanding why.

              – Lundin
              3 hours ago














            4












            4








            4







            You are right.



            C17 draft § 6.5:






            1. An object shall have its stored value accessed only by an lvalue expression that has one of the
              following types: 89)




              • a type compatible with the effective type of the object,


              • a qualified version of a type compatible with the effective type of the object,


              • a type that is the signed or unsigned type corresponding to the effective type of the object,


              • a type that is the signed or unsigned type corresponding to a qualified version of the effective
                type of the object,


              • an aggregate or union type that includes one of the aforementioned types among its members
                (including, recursively, a member of a subaggregate or contained union), or

              • a character type.






            In this case the object is of type uint8_t and type of the lvalue expression is Message. None of the exceptions above apply.



            Using memcpy over dereferences fixes this issue, or alternatively you can disable the strict aliasing in your compiler if you want to write in non-C language.



            But even after this the code has a lot of problems and is not portable: Bitfields are extremely poorly defined in standard and overall structures are very clumsy way to handle serialization. You should take the option of deserializing each member manually.






            share|improve this answer













            You are right.



            C17 draft § 6.5:






            1. An object shall have its stored value accessed only by an lvalue expression that has one of the
              following types: 89)




              • a type compatible with the effective type of the object,


              • a qualified version of a type compatible with the effective type of the object,


              • a type that is the signed or unsigned type corresponding to the effective type of the object,


              • a type that is the signed or unsigned type corresponding to a qualified version of the effective
                type of the object,


              • an aggregate or union type that includes one of the aforementioned types among its members
                (including, recursively, a member of a subaggregate or contained union), or

              • a character type.






            In this case the object is of type uint8_t and type of the lvalue expression is Message. None of the exceptions above apply.



            Using memcpy over dereferences fixes this issue, or alternatively you can disable the strict aliasing in your compiler if you want to write in non-C language.



            But even after this the code has a lot of problems and is not portable: Bitfields are extremely poorly defined in standard and overall structures are very clumsy way to handle serialization. You should take the option of deserializing each member manually.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered 4 hours ago









            user694733user694733

            10.9k12750




            10.9k12750













            • In all fairness, disabling strict aliasing is not a bad idea at all. In particularly or embedded systems design, which this appears to be. Strict aliasing/effective type is a broken part of the C language, specified by PC programmers who don't grasp the type punning often needed in embedded systems. In addition, GCC is the only compiler I know of which abuses strict aliasing to produce faster code that does not at all perform what the unaware programmer intended. But it does so efficiently! Better to always use gcc -fno-strict-aliasing.

              – Lundin
              4 hours ago











            • @Lundin But the flip side of that is programmers with no experience on systems where violating strict aliasing causes actual problems. Thus you get questions like this one, where a bunch of programmers with apparently no understanding at all regarding strict aliasing looks to have prompted someone who does understand the implications to post a question on Stackoverflow.

              – Andrew Henle
              4 hours ago











            • @AndrewHenle But the strict aliasing rule isn't really common knowledge. It takes a hardened C veteran/language nerd to know about it and understand it. Which in turn makes it a safety hazard and language flaw. Particularly since prior C99, no compiler did aggressive optimizations relying on it... and it took around 10 years for C99 to become industry standard. We didn't really see strict aliasing bugs in embedded systems until around 2009, when gcc started to become popular as ARM compiler. And so the non-nerds have to use MISRA-C to tell them "don't do this" without understanding why.

              – Lundin
              3 hours ago



















            • In all fairness, disabling strict aliasing is not a bad idea at all. In particularly or embedded systems design, which this appears to be. Strict aliasing/effective type is a broken part of the C language, specified by PC programmers who don't grasp the type punning often needed in embedded systems. In addition, GCC is the only compiler I know of which abuses strict aliasing to produce faster code that does not at all perform what the unaware programmer intended. But it does so efficiently! Better to always use gcc -fno-strict-aliasing.

              – Lundin
              4 hours ago











            • @Lundin But the flip side of that is programmers with no experience on systems where violating strict aliasing causes actual problems. Thus you get questions like this one, where a bunch of programmers with apparently no understanding at all regarding strict aliasing looks to have prompted someone who does understand the implications to post a question on Stackoverflow.

              – Andrew Henle
              4 hours ago











            • @AndrewHenle But the strict aliasing rule isn't really common knowledge. It takes a hardened C veteran/language nerd to know about it and understand it. Which in turn makes it a safety hazard and language flaw. Particularly since prior C99, no compiler did aggressive optimizations relying on it... and it took around 10 years for C99 to become industry standard. We didn't really see strict aliasing bugs in embedded systems until around 2009, when gcc started to become popular as ARM compiler. And so the non-nerds have to use MISRA-C to tell them "don't do this" without understanding why.

              – Lundin
              3 hours ago

















            In all fairness, disabling strict aliasing is not a bad idea at all. In particularly or embedded systems design, which this appears to be. Strict aliasing/effective type is a broken part of the C language, specified by PC programmers who don't grasp the type punning often needed in embedded systems. In addition, GCC is the only compiler I know of which abuses strict aliasing to produce faster code that does not at all perform what the unaware programmer intended. But it does so efficiently! Better to always use gcc -fno-strict-aliasing.

            – Lundin
            4 hours ago





            In all fairness, disabling strict aliasing is not a bad idea at all. In particularly or embedded systems design, which this appears to be. Strict aliasing/effective type is a broken part of the C language, specified by PC programmers who don't grasp the type punning often needed in embedded systems. In addition, GCC is the only compiler I know of which abuses strict aliasing to produce faster code that does not at all perform what the unaware programmer intended. But it does so efficiently! Better to always use gcc -fno-strict-aliasing.

            – Lundin
            4 hours ago













            @Lundin But the flip side of that is programmers with no experience on systems where violating strict aliasing causes actual problems. Thus you get questions like this one, where a bunch of programmers with apparently no understanding at all regarding strict aliasing looks to have prompted someone who does understand the implications to post a question on Stackoverflow.

            – Andrew Henle
            4 hours ago





            @Lundin But the flip side of that is programmers with no experience on systems where violating strict aliasing causes actual problems. Thus you get questions like this one, where a bunch of programmers with apparently no understanding at all regarding strict aliasing looks to have prompted someone who does understand the implications to post a question on Stackoverflow.

            – Andrew Henle
            4 hours ago













            @AndrewHenle But the strict aliasing rule isn't really common knowledge. It takes a hardened C veteran/language nerd to know about it and understand it. Which in turn makes it a safety hazard and language flaw. Particularly since prior C99, no compiler did aggressive optimizations relying on it... and it took around 10 years for C99 to become industry standard. We didn't really see strict aliasing bugs in embedded systems until around 2009, when gcc started to become popular as ARM compiler. And so the non-nerds have to use MISRA-C to tell them "don't do this" without understanding why.

            – Lundin
            3 hours ago





            @AndrewHenle But the strict aliasing rule isn't really common knowledge. It takes a hardened C veteran/language nerd to know about it and understand it. Which in turn makes it a safety hazard and language flaw. Particularly since prior C99, no compiler did aggressive optimizations relying on it... and it took around 10 years for C99 to become industry standard. We didn't really see strict aliasing bugs in embedded systems until around 2009, when gcc started to become popular as ARM compiler. And so the non-nerds have to use MISRA-C to tell them "don't do this" without understanding why.

            – Lundin
            3 hours ago


















            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%2f54237004%2fstrict-aliasing-rule-uint8-t-buffer-to-structure%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

            Magento 2 controller redirect on button click in phtml file

            Polycentropodidae