Is this type punning well defined?












11















I have structure like below.



struct result{
int a;
int b;
int c;
int d;
}


and union like below.



union convert{
int arr[4];
struct result res;
}


and I type pun as below.



  int arr1[4] = {1,2,3,5};
union convert *pointer = (union convert *) arr1; // Here is my question, is it well defined?

printf("%d %dn", pointer->res.a, pointer->res.b);









share|improve this question

























  • @StoryTeller I'm sorry, it typing mistake.

    – KBlr
    2 days ago






  • 2





    Id you can assure no paddign in the structure - it is safe at list with gcc

    – P__J__
    2 days ago











  • @AndyG; You're correct on the first point, but on the second, doesn't {1,2,3,5} initialise the array?

    – Bathsheba
    2 days ago






  • 1





    @Bathsheba: Darn me and me illiteracy

    – AndyG
    2 days ago






  • 1





    Hmmm, If static_assert(sizeof(convert.arr) == sizeof(convert.res), "Hmmm"); was added, I think the concern about padding is gone - Code would simply not compile when padding occurred.

    – chux
    2 days ago
















11















I have structure like below.



struct result{
int a;
int b;
int c;
int d;
}


and union like below.



union convert{
int arr[4];
struct result res;
}


and I type pun as below.



  int arr1[4] = {1,2,3,5};
union convert *pointer = (union convert *) arr1; // Here is my question, is it well defined?

printf("%d %dn", pointer->res.a, pointer->res.b);









share|improve this question

























  • @StoryTeller I'm sorry, it typing mistake.

    – KBlr
    2 days ago






  • 2





    Id you can assure no paddign in the structure - it is safe at list with gcc

    – P__J__
    2 days ago











  • @AndyG; You're correct on the first point, but on the second, doesn't {1,2,3,5} initialise the array?

    – Bathsheba
    2 days ago






  • 1





    @Bathsheba: Darn me and me illiteracy

    – AndyG
    2 days ago






  • 1





    Hmmm, If static_assert(sizeof(convert.arr) == sizeof(convert.res), "Hmmm"); was added, I think the concern about padding is gone - Code would simply not compile when padding occurred.

    – chux
    2 days ago














11












11








11








I have structure like below.



struct result{
int a;
int b;
int c;
int d;
}


and union like below.



union convert{
int arr[4];
struct result res;
}


and I type pun as below.



  int arr1[4] = {1,2,3,5};
union convert *pointer = (union convert *) arr1; // Here is my question, is it well defined?

printf("%d %dn", pointer->res.a, pointer->res.b);









share|improve this question
















I have structure like below.



struct result{
int a;
int b;
int c;
int d;
}


and union like below.



union convert{
int arr[4];
struct result res;
}


and I type pun as below.



  int arr1[4] = {1,2,3,5};
union convert *pointer = (union convert *) arr1; // Here is my question, is it well defined?

printf("%d %dn", pointer->res.a, pointer->res.b);






c language-lawyer






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 2 days ago









AndyG

26.3k76995




26.3k76995










asked 2 days ago









KBlrKBlr

1699




1699













  • @StoryTeller I'm sorry, it typing mistake.

    – KBlr
    2 days ago






  • 2





    Id you can assure no paddign in the structure - it is safe at list with gcc

    – P__J__
    2 days ago











  • @AndyG; You're correct on the first point, but on the second, doesn't {1,2,3,5} initialise the array?

    – Bathsheba
    2 days ago






  • 1





    @Bathsheba: Darn me and me illiteracy

    – AndyG
    2 days ago






  • 1





    Hmmm, If static_assert(sizeof(convert.arr) == sizeof(convert.res), "Hmmm"); was added, I think the concern about padding is gone - Code would simply not compile when padding occurred.

    – chux
    2 days ago



















  • @StoryTeller I'm sorry, it typing mistake.

    – KBlr
    2 days ago






  • 2





    Id you can assure no paddign in the structure - it is safe at list with gcc

    – P__J__
    2 days ago











  • @AndyG; You're correct on the first point, but on the second, doesn't {1,2,3,5} initialise the array?

    – Bathsheba
    2 days ago






  • 1





    @Bathsheba: Darn me and me illiteracy

    – AndyG
    2 days ago






  • 1





    Hmmm, If static_assert(sizeof(convert.arr) == sizeof(convert.res), "Hmmm"); was added, I think the concern about padding is gone - Code would simply not compile when padding occurred.

    – chux
    2 days ago

















@StoryTeller I'm sorry, it typing mistake.

– KBlr
2 days ago





@StoryTeller I'm sorry, it typing mistake.

– KBlr
2 days ago




2




2





Id you can assure no paddign in the structure - it is safe at list with gcc

– P__J__
2 days ago





Id you can assure no paddign in the structure - it is safe at list with gcc

– P__J__
2 days ago













@AndyG; You're correct on the first point, but on the second, doesn't {1,2,3,5} initialise the array?

– Bathsheba
2 days ago





@AndyG; You're correct on the first point, but on the second, doesn't {1,2,3,5} initialise the array?

– Bathsheba
2 days ago




1




1





@Bathsheba: Darn me and me illiteracy

– AndyG
2 days ago





@Bathsheba: Darn me and me illiteracy

– AndyG
2 days ago




1




1





Hmmm, If static_assert(sizeof(convert.arr) == sizeof(convert.res), "Hmmm"); was added, I think the concern about padding is gone - Code would simply not compile when padding occurred.

– chux
2 days ago





Hmmm, If static_assert(sizeof(convert.arr) == sizeof(convert.res), "Hmmm"); was added, I think the concern about padding is gone - Code would simply not compile when padding occurred.

– chux
2 days ago












4 Answers
4






active

oldest

votes


















12














pointer->res.a is fine but the behaviour of pointer->res.b is undefined.



There could be an arbitrary amount of padding between the a and b members.



Some compilers allow you to specify that there is no padding between members but of course then you are giving up portability.






share|improve this answer



















  • 1





    @KBlr: Yep! Just not portable

    – AndyG
    2 days ago






  • 3





    pointer->res.a accesses an object (arr1) through an lvalue (pointer->res) in violation of C 2018 6.5 7.

    – Eric Postpischil
    2 days ago








  • 1





    @EricPostpischil So the aliasing rule applies not only to the "final" expression which is actually used to access (read or modify) an object, but to all glvalue subexpressions of the "final" expression?

    – Language Lawyer
    2 days ago






  • 1





    @EricPostpischil What I don't like in this aliasing rules, they talk about "expression used to access". I'm not sure does it mean only the "final" expression or all the subexpressions are also "used to access". Any authoritative references here? Also, arrays of different structures with identical definitions did not understand this.

    – Language Lawyer
    2 days ago






  • 1





    @LanguageLawyer: struct A { int x; }; and struct B { int x; }; have identical definitions but are different types. The C standard says they are not compatible, and one may not alias the other. If only the int x mattered, the aliasing rule would be useless. It is the fact that one structure cannot alias the other that enables optimization based on the aliasing rules. The aliasing rules must apply to the structures lvalues, not just the int.

    – Eric Postpischil
    2 days ago



















5















Is this type punning well defined?




struct result{
int a,b,c,d;
}

union convert {
int arr[4];
struct result res;
}

int arr1[4] = {1,2,3,5};
union convert *pointer = (union convert *) arr1;


(union convert *) arr1 risks alignment failure.




A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. C11dr §6.3.2.3 8




There is no requirement that union convert and int share the same alignment. union convert requirements may exceed int for example.



Consider this possibility: arr1 lives on int street where all addresses are multiple of 4. union and struct friends lives on "multiple of 8" street. arr1 might have address 0x1004 (not a multiple of 8).



In 2019, alignment failures are more commonly seen with char (needing 1) and other types needing 2 or more. In OP's select case, I doubt a real platform will have alignment issues, yet incorrect alignment remains possible.



This type punning is not well defined.





Additional concerns



Other answers and comments discuss padding issues, which further identifies trouble.



@Eric Postpischil comment about improper access with pointer->res.a adds more reasons to consider this UB.






share|improve this answer

































    2














    C imposes no rule about how much padding is left between 2 consecutive members of a structure.



    This is why the implementations define many #pragma directives -- specially to change this behaviour.



    So, as the answer of Bathsheba says, ...->b is undefined.



    I answered the very same question some time ago, here.






    share|improve this answer

































      1














      Pointer punning is not safe. Use real union punning instead.



      Assumptions: the struct is properly packed (no padding between the members)



      #include <stdio.h>
      #include <string.h>



      struct __attribute__((packed)) result{
      int a;
      int b;
      int c;
      int d;
      };

      union convert{
      int arr[4];
      struct result res;
      };

      volatile int arr1[4];

      void foo(void)
      {

      union convert cnv;

      memcpy(&cnv, (void *)arr1, sizeof(arr1));

      printf("%d %dn", cnv.res.a, cnv.res.b);
      }


      all modern compilers will optimize out the memcpy call



      https://godbolt.org/z/4qtRIF



      .LC0:
      .string "%d %dn"
      foo:
      mov rsi, QWORD PTR arr1[rip]
      xor eax, eax
      mov rdi, QWORD PTR arr1[rip+8]
      mov edi, OFFSET FLAT:.LC0
      mov rdx, rsi
      sar rdx, 32
      jmp printf





      share|improve this answer
























      • Why the volatile global?

        – curiousguy
        yesterday











      • to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.

        – P__J__
        yesterday











      • I don't follow you.

        – curiousguy
        yesterday











      • @curiousguy so you need to read more about the optimizations. Try to remove the volatile and see what will happen. Try yourself that is the only way

        – P__J__
        yesterday











      • Actually you are the one who needs to read more.

        – curiousguy
        yesterday











      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%2f54237976%2fis-this-type-punning-well-defined%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      4 Answers
      4






      active

      oldest

      votes








      4 Answers
      4






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      12














      pointer->res.a is fine but the behaviour of pointer->res.b is undefined.



      There could be an arbitrary amount of padding between the a and b members.



      Some compilers allow you to specify that there is no padding between members but of course then you are giving up portability.






      share|improve this answer



















      • 1





        @KBlr: Yep! Just not portable

        – AndyG
        2 days ago






      • 3





        pointer->res.a accesses an object (arr1) through an lvalue (pointer->res) in violation of C 2018 6.5 7.

        – Eric Postpischil
        2 days ago








      • 1





        @EricPostpischil So the aliasing rule applies not only to the "final" expression which is actually used to access (read or modify) an object, but to all glvalue subexpressions of the "final" expression?

        – Language Lawyer
        2 days ago






      • 1





        @EricPostpischil What I don't like in this aliasing rules, they talk about "expression used to access". I'm not sure does it mean only the "final" expression or all the subexpressions are also "used to access". Any authoritative references here? Also, arrays of different structures with identical definitions did not understand this.

        – Language Lawyer
        2 days ago






      • 1





        @LanguageLawyer: struct A { int x; }; and struct B { int x; }; have identical definitions but are different types. The C standard says they are not compatible, and one may not alias the other. If only the int x mattered, the aliasing rule would be useless. It is the fact that one structure cannot alias the other that enables optimization based on the aliasing rules. The aliasing rules must apply to the structures lvalues, not just the int.

        – Eric Postpischil
        2 days ago
















      12














      pointer->res.a is fine but the behaviour of pointer->res.b is undefined.



      There could be an arbitrary amount of padding between the a and b members.



      Some compilers allow you to specify that there is no padding between members but of course then you are giving up portability.






      share|improve this answer



















      • 1





        @KBlr: Yep! Just not portable

        – AndyG
        2 days ago






      • 3





        pointer->res.a accesses an object (arr1) through an lvalue (pointer->res) in violation of C 2018 6.5 7.

        – Eric Postpischil
        2 days ago








      • 1





        @EricPostpischil So the aliasing rule applies not only to the "final" expression which is actually used to access (read or modify) an object, but to all glvalue subexpressions of the "final" expression?

        – Language Lawyer
        2 days ago






      • 1





        @EricPostpischil What I don't like in this aliasing rules, they talk about "expression used to access". I'm not sure does it mean only the "final" expression or all the subexpressions are also "used to access". Any authoritative references here? Also, arrays of different structures with identical definitions did not understand this.

        – Language Lawyer
        2 days ago






      • 1





        @LanguageLawyer: struct A { int x; }; and struct B { int x; }; have identical definitions but are different types. The C standard says they are not compatible, and one may not alias the other. If only the int x mattered, the aliasing rule would be useless. It is the fact that one structure cannot alias the other that enables optimization based on the aliasing rules. The aliasing rules must apply to the structures lvalues, not just the int.

        – Eric Postpischil
        2 days ago














      12












      12








      12







      pointer->res.a is fine but the behaviour of pointer->res.b is undefined.



      There could be an arbitrary amount of padding between the a and b members.



      Some compilers allow you to specify that there is no padding between members but of course then you are giving up portability.






      share|improve this answer













      pointer->res.a is fine but the behaviour of pointer->res.b is undefined.



      There could be an arbitrary amount of padding between the a and b members.



      Some compilers allow you to specify that there is no padding between members but of course then you are giving up portability.







      share|improve this answer












      share|improve this answer



      share|improve this answer










      answered 2 days ago









      BathshebaBathsheba

      176k27252376




      176k27252376








      • 1





        @KBlr: Yep! Just not portable

        – AndyG
        2 days ago






      • 3





        pointer->res.a accesses an object (arr1) through an lvalue (pointer->res) in violation of C 2018 6.5 7.

        – Eric Postpischil
        2 days ago








      • 1





        @EricPostpischil So the aliasing rule applies not only to the "final" expression which is actually used to access (read or modify) an object, but to all glvalue subexpressions of the "final" expression?

        – Language Lawyer
        2 days ago






      • 1





        @EricPostpischil What I don't like in this aliasing rules, they talk about "expression used to access". I'm not sure does it mean only the "final" expression or all the subexpressions are also "used to access". Any authoritative references here? Also, arrays of different structures with identical definitions did not understand this.

        – Language Lawyer
        2 days ago






      • 1





        @LanguageLawyer: struct A { int x; }; and struct B { int x; }; have identical definitions but are different types. The C standard says they are not compatible, and one may not alias the other. If only the int x mattered, the aliasing rule would be useless. It is the fact that one structure cannot alias the other that enables optimization based on the aliasing rules. The aliasing rules must apply to the structures lvalues, not just the int.

        – Eric Postpischil
        2 days ago














      • 1





        @KBlr: Yep! Just not portable

        – AndyG
        2 days ago






      • 3





        pointer->res.a accesses an object (arr1) through an lvalue (pointer->res) in violation of C 2018 6.5 7.

        – Eric Postpischil
        2 days ago








      • 1





        @EricPostpischil So the aliasing rule applies not only to the "final" expression which is actually used to access (read or modify) an object, but to all glvalue subexpressions of the "final" expression?

        – Language Lawyer
        2 days ago






      • 1





        @EricPostpischil What I don't like in this aliasing rules, they talk about "expression used to access". I'm not sure does it mean only the "final" expression or all the subexpressions are also "used to access". Any authoritative references here? Also, arrays of different structures with identical definitions did not understand this.

        – Language Lawyer
        2 days ago






      • 1





        @LanguageLawyer: struct A { int x; }; and struct B { int x; }; have identical definitions but are different types. The C standard says they are not compatible, and one may not alias the other. If only the int x mattered, the aliasing rule would be useless. It is the fact that one structure cannot alias the other that enables optimization based on the aliasing rules. The aliasing rules must apply to the structures lvalues, not just the int.

        – Eric Postpischil
        2 days ago








      1




      1





      @KBlr: Yep! Just not portable

      – AndyG
      2 days ago





      @KBlr: Yep! Just not portable

      – AndyG
      2 days ago




      3




      3





      pointer->res.a accesses an object (arr1) through an lvalue (pointer->res) in violation of C 2018 6.5 7.

      – Eric Postpischil
      2 days ago







      pointer->res.a accesses an object (arr1) through an lvalue (pointer->res) in violation of C 2018 6.5 7.

      – Eric Postpischil
      2 days ago






      1




      1





      @EricPostpischil So the aliasing rule applies not only to the "final" expression which is actually used to access (read or modify) an object, but to all glvalue subexpressions of the "final" expression?

      – Language Lawyer
      2 days ago





      @EricPostpischil So the aliasing rule applies not only to the "final" expression which is actually used to access (read or modify) an object, but to all glvalue subexpressions of the "final" expression?

      – Language Lawyer
      2 days ago




      1




      1





      @EricPostpischil What I don't like in this aliasing rules, they talk about "expression used to access". I'm not sure does it mean only the "final" expression or all the subexpressions are also "used to access". Any authoritative references here? Also, arrays of different structures with identical definitions did not understand this.

      – Language Lawyer
      2 days ago





      @EricPostpischil What I don't like in this aliasing rules, they talk about "expression used to access". I'm not sure does it mean only the "final" expression or all the subexpressions are also "used to access". Any authoritative references here? Also, arrays of different structures with identical definitions did not understand this.

      – Language Lawyer
      2 days ago




      1




      1





      @LanguageLawyer: struct A { int x; }; and struct B { int x; }; have identical definitions but are different types. The C standard says they are not compatible, and one may not alias the other. If only the int x mattered, the aliasing rule would be useless. It is the fact that one structure cannot alias the other that enables optimization based on the aliasing rules. The aliasing rules must apply to the structures lvalues, not just the int.

      – Eric Postpischil
      2 days ago





      @LanguageLawyer: struct A { int x; }; and struct B { int x; }; have identical definitions but are different types. The C standard says they are not compatible, and one may not alias the other. If only the int x mattered, the aliasing rule would be useless. It is the fact that one structure cannot alias the other that enables optimization based on the aliasing rules. The aliasing rules must apply to the structures lvalues, not just the int.

      – Eric Postpischil
      2 days ago













      5















      Is this type punning well defined?




      struct result{
      int a,b,c,d;
      }

      union convert {
      int arr[4];
      struct result res;
      }

      int arr1[4] = {1,2,3,5};
      union convert *pointer = (union convert *) arr1;


      (union convert *) arr1 risks alignment failure.




      A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. C11dr §6.3.2.3 8




      There is no requirement that union convert and int share the same alignment. union convert requirements may exceed int for example.



      Consider this possibility: arr1 lives on int street where all addresses are multiple of 4. union and struct friends lives on "multiple of 8" street. arr1 might have address 0x1004 (not a multiple of 8).



      In 2019, alignment failures are more commonly seen with char (needing 1) and other types needing 2 or more. In OP's select case, I doubt a real platform will have alignment issues, yet incorrect alignment remains possible.



      This type punning is not well defined.





      Additional concerns



      Other answers and comments discuss padding issues, which further identifies trouble.



      @Eric Postpischil comment about improper access with pointer->res.a adds more reasons to consider this UB.






      share|improve this answer






























        5















        Is this type punning well defined?




        struct result{
        int a,b,c,d;
        }

        union convert {
        int arr[4];
        struct result res;
        }

        int arr1[4] = {1,2,3,5};
        union convert *pointer = (union convert *) arr1;


        (union convert *) arr1 risks alignment failure.




        A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. C11dr §6.3.2.3 8




        There is no requirement that union convert and int share the same alignment. union convert requirements may exceed int for example.



        Consider this possibility: arr1 lives on int street where all addresses are multiple of 4. union and struct friends lives on "multiple of 8" street. arr1 might have address 0x1004 (not a multiple of 8).



        In 2019, alignment failures are more commonly seen with char (needing 1) and other types needing 2 or more. In OP's select case, I doubt a real platform will have alignment issues, yet incorrect alignment remains possible.



        This type punning is not well defined.





        Additional concerns



        Other answers and comments discuss padding issues, which further identifies trouble.



        @Eric Postpischil comment about improper access with pointer->res.a adds more reasons to consider this UB.






        share|improve this answer




























          5












          5








          5








          Is this type punning well defined?




          struct result{
          int a,b,c,d;
          }

          union convert {
          int arr[4];
          struct result res;
          }

          int arr1[4] = {1,2,3,5};
          union convert *pointer = (union convert *) arr1;


          (union convert *) arr1 risks alignment failure.




          A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. C11dr §6.3.2.3 8




          There is no requirement that union convert and int share the same alignment. union convert requirements may exceed int for example.



          Consider this possibility: arr1 lives on int street where all addresses are multiple of 4. union and struct friends lives on "multiple of 8" street. arr1 might have address 0x1004 (not a multiple of 8).



          In 2019, alignment failures are more commonly seen with char (needing 1) and other types needing 2 or more. In OP's select case, I doubt a real platform will have alignment issues, yet incorrect alignment remains possible.



          This type punning is not well defined.





          Additional concerns



          Other answers and comments discuss padding issues, which further identifies trouble.



          @Eric Postpischil comment about improper access with pointer->res.a adds more reasons to consider this UB.






          share|improve this answer
















          Is this type punning well defined?




          struct result{
          int a,b,c,d;
          }

          union convert {
          int arr[4];
          struct result res;
          }

          int arr1[4] = {1,2,3,5};
          union convert *pointer = (union convert *) arr1;


          (union convert *) arr1 risks alignment failure.




          A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. C11dr §6.3.2.3 8




          There is no requirement that union convert and int share the same alignment. union convert requirements may exceed int for example.



          Consider this possibility: arr1 lives on int street where all addresses are multiple of 4. union and struct friends lives on "multiple of 8" street. arr1 might have address 0x1004 (not a multiple of 8).



          In 2019, alignment failures are more commonly seen with char (needing 1) and other types needing 2 or more. In OP's select case, I doubt a real platform will have alignment issues, yet incorrect alignment remains possible.



          This type punning is not well defined.





          Additional concerns



          Other answers and comments discuss padding issues, which further identifies trouble.



          @Eric Postpischil comment about improper access with pointer->res.a adds more reasons to consider this UB.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited 2 days ago

























          answered 2 days ago









          chuxchux

          81.7k871148




          81.7k871148























              2














              C imposes no rule about how much padding is left between 2 consecutive members of a structure.



              This is why the implementations define many #pragma directives -- specially to change this behaviour.



              So, as the answer of Bathsheba says, ...->b is undefined.



              I answered the very same question some time ago, here.






              share|improve this answer






























                2














                C imposes no rule about how much padding is left between 2 consecutive members of a structure.



                This is why the implementations define many #pragma directives -- specially to change this behaviour.



                So, as the answer of Bathsheba says, ...->b is undefined.



                I answered the very same question some time ago, here.






                share|improve this answer




























                  2












                  2








                  2







                  C imposes no rule about how much padding is left between 2 consecutive members of a structure.



                  This is why the implementations define many #pragma directives -- specially to change this behaviour.



                  So, as the answer of Bathsheba says, ...->b is undefined.



                  I answered the very same question some time ago, here.






                  share|improve this answer















                  C imposes no rule about how much padding is left between 2 consecutive members of a structure.



                  This is why the implementations define many #pragma directives -- specially to change this behaviour.



                  So, as the answer of Bathsheba says, ...->b is undefined.



                  I answered the very same question some time ago, here.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited 2 days ago

























                  answered 2 days ago









                  alinsoaralinsoar

                  8,12613047




                  8,12613047























                      1














                      Pointer punning is not safe. Use real union punning instead.



                      Assumptions: the struct is properly packed (no padding between the members)



                      #include <stdio.h>
                      #include <string.h>



                      struct __attribute__((packed)) result{
                      int a;
                      int b;
                      int c;
                      int d;
                      };

                      union convert{
                      int arr[4];
                      struct result res;
                      };

                      volatile int arr1[4];

                      void foo(void)
                      {

                      union convert cnv;

                      memcpy(&cnv, (void *)arr1, sizeof(arr1));

                      printf("%d %dn", cnv.res.a, cnv.res.b);
                      }


                      all modern compilers will optimize out the memcpy call



                      https://godbolt.org/z/4qtRIF



                      .LC0:
                      .string "%d %dn"
                      foo:
                      mov rsi, QWORD PTR arr1[rip]
                      xor eax, eax
                      mov rdi, QWORD PTR arr1[rip+8]
                      mov edi, OFFSET FLAT:.LC0
                      mov rdx, rsi
                      sar rdx, 32
                      jmp printf





                      share|improve this answer
























                      • Why the volatile global?

                        – curiousguy
                        yesterday











                      • to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.

                        – P__J__
                        yesterday











                      • I don't follow you.

                        – curiousguy
                        yesterday











                      • @curiousguy so you need to read more about the optimizations. Try to remove the volatile and see what will happen. Try yourself that is the only way

                        – P__J__
                        yesterday











                      • Actually you are the one who needs to read more.

                        – curiousguy
                        yesterday
















                      1














                      Pointer punning is not safe. Use real union punning instead.



                      Assumptions: the struct is properly packed (no padding between the members)



                      #include <stdio.h>
                      #include <string.h>



                      struct __attribute__((packed)) result{
                      int a;
                      int b;
                      int c;
                      int d;
                      };

                      union convert{
                      int arr[4];
                      struct result res;
                      };

                      volatile int arr1[4];

                      void foo(void)
                      {

                      union convert cnv;

                      memcpy(&cnv, (void *)arr1, sizeof(arr1));

                      printf("%d %dn", cnv.res.a, cnv.res.b);
                      }


                      all modern compilers will optimize out the memcpy call



                      https://godbolt.org/z/4qtRIF



                      .LC0:
                      .string "%d %dn"
                      foo:
                      mov rsi, QWORD PTR arr1[rip]
                      xor eax, eax
                      mov rdi, QWORD PTR arr1[rip+8]
                      mov edi, OFFSET FLAT:.LC0
                      mov rdx, rsi
                      sar rdx, 32
                      jmp printf





                      share|improve this answer
























                      • Why the volatile global?

                        – curiousguy
                        yesterday











                      • to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.

                        – P__J__
                        yesterday











                      • I don't follow you.

                        – curiousguy
                        yesterday











                      • @curiousguy so you need to read more about the optimizations. Try to remove the volatile and see what will happen. Try yourself that is the only way

                        – P__J__
                        yesterday











                      • Actually you are the one who needs to read more.

                        – curiousguy
                        yesterday














                      1












                      1








                      1







                      Pointer punning is not safe. Use real union punning instead.



                      Assumptions: the struct is properly packed (no padding between the members)



                      #include <stdio.h>
                      #include <string.h>



                      struct __attribute__((packed)) result{
                      int a;
                      int b;
                      int c;
                      int d;
                      };

                      union convert{
                      int arr[4];
                      struct result res;
                      };

                      volatile int arr1[4];

                      void foo(void)
                      {

                      union convert cnv;

                      memcpy(&cnv, (void *)arr1, sizeof(arr1));

                      printf("%d %dn", cnv.res.a, cnv.res.b);
                      }


                      all modern compilers will optimize out the memcpy call



                      https://godbolt.org/z/4qtRIF



                      .LC0:
                      .string "%d %dn"
                      foo:
                      mov rsi, QWORD PTR arr1[rip]
                      xor eax, eax
                      mov rdi, QWORD PTR arr1[rip+8]
                      mov edi, OFFSET FLAT:.LC0
                      mov rdx, rsi
                      sar rdx, 32
                      jmp printf





                      share|improve this answer













                      Pointer punning is not safe. Use real union punning instead.



                      Assumptions: the struct is properly packed (no padding between the members)



                      #include <stdio.h>
                      #include <string.h>



                      struct __attribute__((packed)) result{
                      int a;
                      int b;
                      int c;
                      int d;
                      };

                      union convert{
                      int arr[4];
                      struct result res;
                      };

                      volatile int arr1[4];

                      void foo(void)
                      {

                      union convert cnv;

                      memcpy(&cnv, (void *)arr1, sizeof(arr1));

                      printf("%d %dn", cnv.res.a, cnv.res.b);
                      }


                      all modern compilers will optimize out the memcpy call



                      https://godbolt.org/z/4qtRIF



                      .LC0:
                      .string "%d %dn"
                      foo:
                      mov rsi, QWORD PTR arr1[rip]
                      xor eax, eax
                      mov rdi, QWORD PTR arr1[rip+8]
                      mov edi, OFFSET FLAT:.LC0
                      mov rdx, rsi
                      sar rdx, 32
                      jmp printf






                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered 2 days ago









                      P__J__P__J__

                      9,6592723




                      9,6592723













                      • Why the volatile global?

                        – curiousguy
                        yesterday











                      • to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.

                        – P__J__
                        yesterday











                      • I don't follow you.

                        – curiousguy
                        yesterday











                      • @curiousguy so you need to read more about the optimizations. Try to remove the volatile and see what will happen. Try yourself that is the only way

                        – P__J__
                        yesterday











                      • Actually you are the one who needs to read more.

                        – curiousguy
                        yesterday



















                      • Why the volatile global?

                        – curiousguy
                        yesterday











                      • to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.

                        – P__J__
                        yesterday











                      • I don't follow you.

                        – curiousguy
                        yesterday











                      • @curiousguy so you need to read more about the optimizations. Try to remove the volatile and see what will happen. Try yourself that is the only way

                        – P__J__
                        yesterday











                      • Actually you are the one who needs to read more.

                        – curiousguy
                        yesterday

















                      Why the volatile global?

                      – curiousguy
                      yesterday





                      Why the volatile global?

                      – curiousguy
                      yesterday













                      to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.

                      – P__J__
                      yesterday





                      to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.

                      – P__J__
                      yesterday













                      I don't follow you.

                      – curiousguy
                      yesterday





                      I don't follow you.

                      – curiousguy
                      yesterday













                      @curiousguy so you need to read more about the optimizations. Try to remove the volatile and see what will happen. Try yourself that is the only way

                      – P__J__
                      yesterday





                      @curiousguy so you need to read more about the optimizations. Try to remove the volatile and see what will happen. Try yourself that is the only way

                      – P__J__
                      yesterday













                      Actually you are the one who needs to read more.

                      – curiousguy
                      yesterday





                      Actually you are the one who needs to read more.

                      – curiousguy
                      yesterday


















                      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%2f54237976%2fis-this-type-punning-well-defined%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

                      "Incorrect syntax near the keyword 'ON'. (on update cascade, on delete cascade,)

                      Alcedinidae

                      Origin of the phrase “under your belt”?