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
    12 hours ago






  • 2





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

    – P__J__
    12 hours ago











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

    – Bathsheba
    12 hours ago






  • 1





    @Bathsheba: Darn me and me illiteracy

    – AndyG
    12 hours 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
    10 hours 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
    12 hours ago






  • 2





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

    – P__J__
    12 hours ago











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

    – Bathsheba
    12 hours ago






  • 1





    @Bathsheba: Darn me and me illiteracy

    – AndyG
    12 hours 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
    10 hours 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 12 hours ago









AndyG

26.2k76995




26.2k76995










asked 12 hours ago









KBlrKBlr

1699




1699













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

    – KBlr
    12 hours ago






  • 2





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

    – P__J__
    12 hours ago











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

    – Bathsheba
    12 hours ago






  • 1





    @Bathsheba: Darn me and me illiteracy

    – AndyG
    12 hours 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
    10 hours ago



















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

    – KBlr
    12 hours ago






  • 2





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

    – P__J__
    12 hours ago











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

    – Bathsheba
    12 hours ago






  • 1





    @Bathsheba: Darn me and me illiteracy

    – AndyG
    12 hours 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
    10 hours ago

















@StoryTeller I'm sorry, it typing mistake.

– KBlr
12 hours ago





@StoryTeller I'm sorry, it typing mistake.

– KBlr
12 hours ago




2




2





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

– P__J__
12 hours ago





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

– P__J__
12 hours ago













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

– Bathsheba
12 hours ago





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

– Bathsheba
12 hours ago




1




1





@Bathsheba: Darn me and me illiteracy

– AndyG
12 hours ago





@Bathsheba: Darn me and me illiteracy

– AndyG
12 hours 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
10 hours 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
10 hours 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
























  • Thank you! If I ensure that there will be no padding is it then well defined?

    – KBlr
    12 hours ago






  • 1





    @KBlr: Yep! Just not portable

    – AndyG
    12 hours ago






  • 3





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

    – Eric Postpischil
    10 hours 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
    8 hours 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
    6 hours 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























        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
























        • Thank you! If I ensure that there will be no padding is it then well defined?

          – KBlr
          12 hours ago






        • 1





          @KBlr: Yep! Just not portable

          – AndyG
          12 hours ago






        • 3





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

          – Eric Postpischil
          10 hours 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
          8 hours 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
          6 hours 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
























        • Thank you! If I ensure that there will be no padding is it then well defined?

          – KBlr
          12 hours ago






        • 1





          @KBlr: Yep! Just not portable

          – AndyG
          12 hours ago






        • 3





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

          – Eric Postpischil
          10 hours 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
          8 hours 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
          6 hours 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 12 hours ago









        BathshebaBathsheba

        176k27251374




        176k27251374













        • Thank you! If I ensure that there will be no padding is it then well defined?

          – KBlr
          12 hours ago






        • 1





          @KBlr: Yep! Just not portable

          – AndyG
          12 hours ago






        • 3





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

          – Eric Postpischil
          10 hours 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
          8 hours 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
          6 hours ago



















        • Thank you! If I ensure that there will be no padding is it then well defined?

          – KBlr
          12 hours ago






        • 1





          @KBlr: Yep! Just not portable

          – AndyG
          12 hours ago






        • 3





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

          – Eric Postpischil
          10 hours 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
          8 hours 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
          6 hours ago

















        Thank you! If I ensure that there will be no padding is it then well defined?

        – KBlr
        12 hours ago





        Thank you! If I ensure that there will be no padding is it then well defined?

        – KBlr
        12 hours ago




        1




        1





        @KBlr: Yep! Just not portable

        – AndyG
        12 hours ago





        @KBlr: Yep! Just not portable

        – AndyG
        12 hours 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
        10 hours ago







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

        – Eric Postpischil
        10 hours 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
        8 hours 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
        8 hours 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
        6 hours 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
        6 hours 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 7 hours ago

























            answered 9 hours ago









            chuxchux

            81.6k871148




            81.6k871148























                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 11 hours ago

























                    answered 12 hours 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




























                          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


























                            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 12 hours ago









                            P__J__P__J__

                            9,5912723




                            9,5912723






























                                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

                                Terni

                                A new problem with tex4ht and tikz

                                Sun Ra