Guaranteed memory layout for standard layout struct with a single array member of primitive type





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







17















Consider the following simple struct:



struct A
{
float data[16];
};


My question is:



Assuming a platform where float is a 32-bit IEEE754 floating point number (if that matters at all), does the C++ standard guarantee the expected memory layout for struct A? If not, what does it guarantee and/or what are the ways to enforce the guarantees?



By the expected memory layout I mean that the struct takes up 16*4=64 bytes in memory, each consecutive 4 bytes occupied by a single float from the data array. In other words, expected memory layout means the following test passes:



static_assert(sizeof(A) == 16 * sizeof(float));
static_assert(offsetof(A, data[0]) == 0 * sizeof(float));
static_assert(offsetof(A, data[1]) == 1 * sizeof(float));
...
static_assert(offsetof(A, data[15]) == 15 * sizeof(float));


(offsetof is legal here since A is standard layout, see below)



In case this bothers you, the test actually passes on wandbox with gcc 9 HEAD. I have never met a combination of a platform and compiler which would provide evidence that this test may fail, and I would love to learn about them in case they do exist.



Why would one even care:




  • SSE-like optimizations require certain memory layout (and alignment, which I ignore in this question, since it can be dealt with using the standard alignas specifier).

  • Serialization of such a struct would simply boil down to a nice and portable write_bytes(&x, sizeof(A)).

  • Some APIs (e.g. OpenGL, specifically, say, glUniformMatrix4fv) expect this exact memory layout. Of course, one could just pass the pointer to data array to pass a single object of this type, but for a sequence of these (say, for uploading matrix-type vertex attributes) a specific memory layout is still needed.


What is actually guaranteed:



These are the things that, to my knowledge, can be expected from struct A:




  • It is standard layout

  • As a consequence of being standard-layout, a pointer to A can be reinterpret_cast to a pointer to its first data member (which is, presumably, data[0] ?), i.e. there is no padding before the first member.


The two remaining guarantees that are not (as to my knowledge) provided by the standard are:




  • There is no padding in between elements of an array of primitive type (I am sure that this is false, but I failed to find a confirmative reference),

  • There is no padding after the data array inside struct A.










share|improve this question




















  • 3





    The first of your two remaining guarantees is guaranteed by C++ 2017 (draft n4659) 11.3.4, “Arrays” [dcl.array]: “An object of array type contains a contiguously allocated non-empty set of N subobjects of type T.” 1998 edition has identical text except with hyphenated “sub-objects” in 8.3.4.

    – Eric Postpischil
    13 hours ago













  • @EricPostpischil Thank you for clarification! What exactly does "contiguously allocated" mean in this context?

    – lisyarus
    13 hours ago













  • @lisyarus: It is “plain English,” or at least English as used by practitioners in the field—it is not formally defined in the standard. I am quite sure it means the bytes of the elements in the array are laid out in memory one after the other with no padding between elements.

    – Eric Postpischil
    13 hours ago






  • 4





    In C, the second of the remaining guarantees is not guaranteed, and there are some reasons a “difficult” C implementation might pad a structure containing a single array. For example, we can imagine an implementation would pad struct { char x[2]; } to four bytes if its target hardware had a strong bias toward four-byte word addressing of memory, and the implementation had decided to make all structures at least four-byte-aligned to satisfy the C standard’s requirement of one representation for all structure pointers. I expect C++ is similar but cannot speak confidently to it…

    – Eric Postpischil
    13 hours ago











  • … and note that is something of a “theoretical” possibility. Most likely, struct { float data[16]; } would not be given any trailing padding by any normal C or C++ implementation—there is no reason for it in any normal target platform. But, in the absence of an explicit specification in the C++ standard, the only way to guarantee it is for the project to require that any C++ implementation used to compile it satisfy this property. It could be tested with an assertion.

    – Eric Postpischil
    13 hours ago




















17















Consider the following simple struct:



struct A
{
float data[16];
};


My question is:



Assuming a platform where float is a 32-bit IEEE754 floating point number (if that matters at all), does the C++ standard guarantee the expected memory layout for struct A? If not, what does it guarantee and/or what are the ways to enforce the guarantees?



By the expected memory layout I mean that the struct takes up 16*4=64 bytes in memory, each consecutive 4 bytes occupied by a single float from the data array. In other words, expected memory layout means the following test passes:



static_assert(sizeof(A) == 16 * sizeof(float));
static_assert(offsetof(A, data[0]) == 0 * sizeof(float));
static_assert(offsetof(A, data[1]) == 1 * sizeof(float));
...
static_assert(offsetof(A, data[15]) == 15 * sizeof(float));


(offsetof is legal here since A is standard layout, see below)



In case this bothers you, the test actually passes on wandbox with gcc 9 HEAD. I have never met a combination of a platform and compiler which would provide evidence that this test may fail, and I would love to learn about them in case they do exist.



Why would one even care:




  • SSE-like optimizations require certain memory layout (and alignment, which I ignore in this question, since it can be dealt with using the standard alignas specifier).

  • Serialization of such a struct would simply boil down to a nice and portable write_bytes(&x, sizeof(A)).

  • Some APIs (e.g. OpenGL, specifically, say, glUniformMatrix4fv) expect this exact memory layout. Of course, one could just pass the pointer to data array to pass a single object of this type, but for a sequence of these (say, for uploading matrix-type vertex attributes) a specific memory layout is still needed.


What is actually guaranteed:



These are the things that, to my knowledge, can be expected from struct A:




  • It is standard layout

  • As a consequence of being standard-layout, a pointer to A can be reinterpret_cast to a pointer to its first data member (which is, presumably, data[0] ?), i.e. there is no padding before the first member.


The two remaining guarantees that are not (as to my knowledge) provided by the standard are:




  • There is no padding in between elements of an array of primitive type (I am sure that this is false, but I failed to find a confirmative reference),

  • There is no padding after the data array inside struct A.










share|improve this question




















  • 3





    The first of your two remaining guarantees is guaranteed by C++ 2017 (draft n4659) 11.3.4, “Arrays” [dcl.array]: “An object of array type contains a contiguously allocated non-empty set of N subobjects of type T.” 1998 edition has identical text except with hyphenated “sub-objects” in 8.3.4.

    – Eric Postpischil
    13 hours ago













  • @EricPostpischil Thank you for clarification! What exactly does "contiguously allocated" mean in this context?

    – lisyarus
    13 hours ago













  • @lisyarus: It is “plain English,” or at least English as used by practitioners in the field—it is not formally defined in the standard. I am quite sure it means the bytes of the elements in the array are laid out in memory one after the other with no padding between elements.

    – Eric Postpischil
    13 hours ago






  • 4





    In C, the second of the remaining guarantees is not guaranteed, and there are some reasons a “difficult” C implementation might pad a structure containing a single array. For example, we can imagine an implementation would pad struct { char x[2]; } to four bytes if its target hardware had a strong bias toward four-byte word addressing of memory, and the implementation had decided to make all structures at least four-byte-aligned to satisfy the C standard’s requirement of one representation for all structure pointers. I expect C++ is similar but cannot speak confidently to it…

    – Eric Postpischil
    13 hours ago











  • … and note that is something of a “theoretical” possibility. Most likely, struct { float data[16]; } would not be given any trailing padding by any normal C or C++ implementation—there is no reason for it in any normal target platform. But, in the absence of an explicit specification in the C++ standard, the only way to guarantee it is for the project to require that any C++ implementation used to compile it satisfy this property. It could be tested with an assertion.

    – Eric Postpischil
    13 hours ago
















17












17








17


4






Consider the following simple struct:



struct A
{
float data[16];
};


My question is:



Assuming a platform where float is a 32-bit IEEE754 floating point number (if that matters at all), does the C++ standard guarantee the expected memory layout for struct A? If not, what does it guarantee and/or what are the ways to enforce the guarantees?



By the expected memory layout I mean that the struct takes up 16*4=64 bytes in memory, each consecutive 4 bytes occupied by a single float from the data array. In other words, expected memory layout means the following test passes:



static_assert(sizeof(A) == 16 * sizeof(float));
static_assert(offsetof(A, data[0]) == 0 * sizeof(float));
static_assert(offsetof(A, data[1]) == 1 * sizeof(float));
...
static_assert(offsetof(A, data[15]) == 15 * sizeof(float));


(offsetof is legal here since A is standard layout, see below)



In case this bothers you, the test actually passes on wandbox with gcc 9 HEAD. I have never met a combination of a platform and compiler which would provide evidence that this test may fail, and I would love to learn about them in case they do exist.



Why would one even care:




  • SSE-like optimizations require certain memory layout (and alignment, which I ignore in this question, since it can be dealt with using the standard alignas specifier).

  • Serialization of such a struct would simply boil down to a nice and portable write_bytes(&x, sizeof(A)).

  • Some APIs (e.g. OpenGL, specifically, say, glUniformMatrix4fv) expect this exact memory layout. Of course, one could just pass the pointer to data array to pass a single object of this type, but for a sequence of these (say, for uploading matrix-type vertex attributes) a specific memory layout is still needed.


What is actually guaranteed:



These are the things that, to my knowledge, can be expected from struct A:




  • It is standard layout

  • As a consequence of being standard-layout, a pointer to A can be reinterpret_cast to a pointer to its first data member (which is, presumably, data[0] ?), i.e. there is no padding before the first member.


The two remaining guarantees that are not (as to my knowledge) provided by the standard are:




  • There is no padding in between elements of an array of primitive type (I am sure that this is false, but I failed to find a confirmative reference),

  • There is no padding after the data array inside struct A.










share|improve this question
















Consider the following simple struct:



struct A
{
float data[16];
};


My question is:



Assuming a platform where float is a 32-bit IEEE754 floating point number (if that matters at all), does the C++ standard guarantee the expected memory layout for struct A? If not, what does it guarantee and/or what are the ways to enforce the guarantees?



By the expected memory layout I mean that the struct takes up 16*4=64 bytes in memory, each consecutive 4 bytes occupied by a single float from the data array. In other words, expected memory layout means the following test passes:



static_assert(sizeof(A) == 16 * sizeof(float));
static_assert(offsetof(A, data[0]) == 0 * sizeof(float));
static_assert(offsetof(A, data[1]) == 1 * sizeof(float));
...
static_assert(offsetof(A, data[15]) == 15 * sizeof(float));


(offsetof is legal here since A is standard layout, see below)



In case this bothers you, the test actually passes on wandbox with gcc 9 HEAD. I have never met a combination of a platform and compiler which would provide evidence that this test may fail, and I would love to learn about them in case they do exist.



Why would one even care:




  • SSE-like optimizations require certain memory layout (and alignment, which I ignore in this question, since it can be dealt with using the standard alignas specifier).

  • Serialization of such a struct would simply boil down to a nice and portable write_bytes(&x, sizeof(A)).

  • Some APIs (e.g. OpenGL, specifically, say, glUniformMatrix4fv) expect this exact memory layout. Of course, one could just pass the pointer to data array to pass a single object of this type, but for a sequence of these (say, for uploading matrix-type vertex attributes) a specific memory layout is still needed.


What is actually guaranteed:



These are the things that, to my knowledge, can be expected from struct A:




  • It is standard layout

  • As a consequence of being standard-layout, a pointer to A can be reinterpret_cast to a pointer to its first data member (which is, presumably, data[0] ?), i.e. there is no padding before the first member.


The two remaining guarantees that are not (as to my knowledge) provided by the standard are:




  • There is no padding in between elements of an array of primitive type (I am sure that this is false, but I failed to find a confirmative reference),

  • There is no padding after the data array inside struct A.







c++ language-lawyer memory-layout standard-layout






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 13 hours ago







lisyarus

















asked 13 hours ago









lisyaruslisyarus

10.5k22952




10.5k22952








  • 3





    The first of your two remaining guarantees is guaranteed by C++ 2017 (draft n4659) 11.3.4, “Arrays” [dcl.array]: “An object of array type contains a contiguously allocated non-empty set of N subobjects of type T.” 1998 edition has identical text except with hyphenated “sub-objects” in 8.3.4.

    – Eric Postpischil
    13 hours ago













  • @EricPostpischil Thank you for clarification! What exactly does "contiguously allocated" mean in this context?

    – lisyarus
    13 hours ago













  • @lisyarus: It is “plain English,” or at least English as used by practitioners in the field—it is not formally defined in the standard. I am quite sure it means the bytes of the elements in the array are laid out in memory one after the other with no padding between elements.

    – Eric Postpischil
    13 hours ago






  • 4





    In C, the second of the remaining guarantees is not guaranteed, and there are some reasons a “difficult” C implementation might pad a structure containing a single array. For example, we can imagine an implementation would pad struct { char x[2]; } to four bytes if its target hardware had a strong bias toward four-byte word addressing of memory, and the implementation had decided to make all structures at least four-byte-aligned to satisfy the C standard’s requirement of one representation for all structure pointers. I expect C++ is similar but cannot speak confidently to it…

    – Eric Postpischil
    13 hours ago











  • … and note that is something of a “theoretical” possibility. Most likely, struct { float data[16]; } would not be given any trailing padding by any normal C or C++ implementation—there is no reason for it in any normal target platform. But, in the absence of an explicit specification in the C++ standard, the only way to guarantee it is for the project to require that any C++ implementation used to compile it satisfy this property. It could be tested with an assertion.

    – Eric Postpischil
    13 hours ago
















  • 3





    The first of your two remaining guarantees is guaranteed by C++ 2017 (draft n4659) 11.3.4, “Arrays” [dcl.array]: “An object of array type contains a contiguously allocated non-empty set of N subobjects of type T.” 1998 edition has identical text except with hyphenated “sub-objects” in 8.3.4.

    – Eric Postpischil
    13 hours ago













  • @EricPostpischil Thank you for clarification! What exactly does "contiguously allocated" mean in this context?

    – lisyarus
    13 hours ago













  • @lisyarus: It is “plain English,” or at least English as used by practitioners in the field—it is not formally defined in the standard. I am quite sure it means the bytes of the elements in the array are laid out in memory one after the other with no padding between elements.

    – Eric Postpischil
    13 hours ago






  • 4





    In C, the second of the remaining guarantees is not guaranteed, and there are some reasons a “difficult” C implementation might pad a structure containing a single array. For example, we can imagine an implementation would pad struct { char x[2]; } to four bytes if its target hardware had a strong bias toward four-byte word addressing of memory, and the implementation had decided to make all structures at least four-byte-aligned to satisfy the C standard’s requirement of one representation for all structure pointers. I expect C++ is similar but cannot speak confidently to it…

    – Eric Postpischil
    13 hours ago











  • … and note that is something of a “theoretical” possibility. Most likely, struct { float data[16]; } would not be given any trailing padding by any normal C or C++ implementation—there is no reason for it in any normal target platform. But, in the absence of an explicit specification in the C++ standard, the only way to guarantee it is for the project to require that any C++ implementation used to compile it satisfy this property. It could be tested with an assertion.

    – Eric Postpischil
    13 hours ago










3




3





The first of your two remaining guarantees is guaranteed by C++ 2017 (draft n4659) 11.3.4, “Arrays” [dcl.array]: “An object of array type contains a contiguously allocated non-empty set of N subobjects of type T.” 1998 edition has identical text except with hyphenated “sub-objects” in 8.3.4.

– Eric Postpischil
13 hours ago







The first of your two remaining guarantees is guaranteed by C++ 2017 (draft n4659) 11.3.4, “Arrays” [dcl.array]: “An object of array type contains a contiguously allocated non-empty set of N subobjects of type T.” 1998 edition has identical text except with hyphenated “sub-objects” in 8.3.4.

– Eric Postpischil
13 hours ago















@EricPostpischil Thank you for clarification! What exactly does "contiguously allocated" mean in this context?

– lisyarus
13 hours ago







@EricPostpischil Thank you for clarification! What exactly does "contiguously allocated" mean in this context?

– lisyarus
13 hours ago















@lisyarus: It is “plain English,” or at least English as used by practitioners in the field—it is not formally defined in the standard. I am quite sure it means the bytes of the elements in the array are laid out in memory one after the other with no padding between elements.

– Eric Postpischil
13 hours ago





@lisyarus: It is “plain English,” or at least English as used by practitioners in the field—it is not formally defined in the standard. I am quite sure it means the bytes of the elements in the array are laid out in memory one after the other with no padding between elements.

– Eric Postpischil
13 hours ago




4




4





In C, the second of the remaining guarantees is not guaranteed, and there are some reasons a “difficult” C implementation might pad a structure containing a single array. For example, we can imagine an implementation would pad struct { char x[2]; } to four bytes if its target hardware had a strong bias toward four-byte word addressing of memory, and the implementation had decided to make all structures at least four-byte-aligned to satisfy the C standard’s requirement of one representation for all structure pointers. I expect C++ is similar but cannot speak confidently to it…

– Eric Postpischil
13 hours ago





In C, the second of the remaining guarantees is not guaranteed, and there are some reasons a “difficult” C implementation might pad a structure containing a single array. For example, we can imagine an implementation would pad struct { char x[2]; } to four bytes if its target hardware had a strong bias toward four-byte word addressing of memory, and the implementation had decided to make all structures at least four-byte-aligned to satisfy the C standard’s requirement of one representation for all structure pointers. I expect C++ is similar but cannot speak confidently to it…

– Eric Postpischil
13 hours ago













… and note that is something of a “theoretical” possibility. Most likely, struct { float data[16]; } would not be given any trailing padding by any normal C or C++ implementation—there is no reason for it in any normal target platform. But, in the absence of an explicit specification in the C++ standard, the only way to guarantee it is for the project to require that any C++ implementation used to compile it satisfy this property. It could be tested with an assertion.

– Eric Postpischil
13 hours ago







… and note that is something of a “theoretical” possibility. Most likely, struct { float data[16]; } would not be given any trailing padding by any normal C or C++ implementation—there is no reason for it in any normal target platform. But, in the absence of an explicit specification in the C++ standard, the only way to guarantee it is for the project to require that any C++ implementation used to compile it satisfy this property. It could be tested with an assertion.

– Eric Postpischil
13 hours ago














2 Answers
2






active

oldest

votes


















9














One thing that is not guaranteed about the layout is endianness i.e. the order of bytes within a multi-byte object. write_bytes(&x, sizeof(A)) is not portable serialisation across systems with different endianness.




A can be reinterpret_cast to a pointer to its first data member (which is, presumably, data[0] ?)




Correction: The first data member is data, which you can reinterpret cast with. And crucially, an array is not pointer-interconvertible with its first element, so you cannot reinterpret cast between them. The address however is guaranteed to be the same, so reinterpreting as data[0] should be fine after std::launder as far as I understand.




There is no padding in between elements of an array of primitive type




Arrays are guaranteed to be contiguous. sizeof of an object is specified in terms of padding required to place elements into an array. sizeof(T[10]) has exactly the size sizeof(T * 10). If there is padding between non-padding bits of adjacent elements, then that padding is at the end of the element itself.



Primitive type is not guaranteed to not have padding in general. For example, the x86 extended precision long double is 80 bits, padded to 128 bits.



char, signed char and unsigned char are guaranteed to not have padding bits. C standard (to which C++ delegates the specification in this case) guarantees that the fixed width intN_t and uintN_t aliases do not have padding bits. On systems where that is not possible, these fixed width types are not provided.






share|improve this answer


























  • Just to be absolutely clear. Is your last paragraph is a direct counter example against 2nd unanswered question? I am asking from a compound type perspective, so for example struct S {char a,b,c;}; if padded to 4*sizeof(char) could have padding at the end. And for that matter we cannot tell relative address of any member other than a, I think they can be reordered an padded as compiler see fit. Yup?

    – luk32
    13 hours ago













  • @luk32 There cannot possibly be a need for padding between char elements, as they have alignment of 1. Any sensible ABI would place the padding (if there is any) of S at the end. But indeed, I don't know of explicit guarantee about that in the C++ standard.

    – eerorika
    12 hours ago













  • Could you, please, elaborate on this usage of std::launder?

    – lisyarus
    9 hours ago











  • @lisyarus en.cppreference.com/w/cpp/utility/launder

    – eerorika
    9 hours ago











  • @eerorika I apologize, but I struggle to understand the reason why std::launder is needed here based on the cppreference article.

    – lisyarus
    9 hours ago



















2















If a standard-layout class object has any non-static data members, its
address is the same as the address of its first non-static data member.
Otherwise, its address is the same as the address of its first base
class subobject (if any). [Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. — end note]




Hence, the standard guarantees that



static_assert(offsetof(A, data[0]) == 0 * sizeof(float));



An object of array type contains a contiguously allocated non-empty
set of N subobjects of type T.




Hence, the following are true



static_assert(offsetof(A, data[0]) == 0 * sizeof(float));
static_assert(offsetof(A, data[1]) == 1 * sizeof(float));
...
static_assert(offsetof(A, data[15]) == 15 * sizeof(float));





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%2f55650798%2fguaranteed-memory-layout-for-standard-layout-struct-with-a-single-array-member-o%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









    9














    One thing that is not guaranteed about the layout is endianness i.e. the order of bytes within a multi-byte object. write_bytes(&x, sizeof(A)) is not portable serialisation across systems with different endianness.




    A can be reinterpret_cast to a pointer to its first data member (which is, presumably, data[0] ?)




    Correction: The first data member is data, which you can reinterpret cast with. And crucially, an array is not pointer-interconvertible with its first element, so you cannot reinterpret cast between them. The address however is guaranteed to be the same, so reinterpreting as data[0] should be fine after std::launder as far as I understand.




    There is no padding in between elements of an array of primitive type




    Arrays are guaranteed to be contiguous. sizeof of an object is specified in terms of padding required to place elements into an array. sizeof(T[10]) has exactly the size sizeof(T * 10). If there is padding between non-padding bits of adjacent elements, then that padding is at the end of the element itself.



    Primitive type is not guaranteed to not have padding in general. For example, the x86 extended precision long double is 80 bits, padded to 128 bits.



    char, signed char and unsigned char are guaranteed to not have padding bits. C standard (to which C++ delegates the specification in this case) guarantees that the fixed width intN_t and uintN_t aliases do not have padding bits. On systems where that is not possible, these fixed width types are not provided.






    share|improve this answer


























    • Just to be absolutely clear. Is your last paragraph is a direct counter example against 2nd unanswered question? I am asking from a compound type perspective, so for example struct S {char a,b,c;}; if padded to 4*sizeof(char) could have padding at the end. And for that matter we cannot tell relative address of any member other than a, I think they can be reordered an padded as compiler see fit. Yup?

      – luk32
      13 hours ago













    • @luk32 There cannot possibly be a need for padding between char elements, as they have alignment of 1. Any sensible ABI would place the padding (if there is any) of S at the end. But indeed, I don't know of explicit guarantee about that in the C++ standard.

      – eerorika
      12 hours ago













    • Could you, please, elaborate on this usage of std::launder?

      – lisyarus
      9 hours ago











    • @lisyarus en.cppreference.com/w/cpp/utility/launder

      – eerorika
      9 hours ago











    • @eerorika I apologize, but I struggle to understand the reason why std::launder is needed here based on the cppreference article.

      – lisyarus
      9 hours ago
















    9














    One thing that is not guaranteed about the layout is endianness i.e. the order of bytes within a multi-byte object. write_bytes(&x, sizeof(A)) is not portable serialisation across systems with different endianness.




    A can be reinterpret_cast to a pointer to its first data member (which is, presumably, data[0] ?)




    Correction: The first data member is data, which you can reinterpret cast with. And crucially, an array is not pointer-interconvertible with its first element, so you cannot reinterpret cast between them. The address however is guaranteed to be the same, so reinterpreting as data[0] should be fine after std::launder as far as I understand.




    There is no padding in between elements of an array of primitive type




    Arrays are guaranteed to be contiguous. sizeof of an object is specified in terms of padding required to place elements into an array. sizeof(T[10]) has exactly the size sizeof(T * 10). If there is padding between non-padding bits of adjacent elements, then that padding is at the end of the element itself.



    Primitive type is not guaranteed to not have padding in general. For example, the x86 extended precision long double is 80 bits, padded to 128 bits.



    char, signed char and unsigned char are guaranteed to not have padding bits. C standard (to which C++ delegates the specification in this case) guarantees that the fixed width intN_t and uintN_t aliases do not have padding bits. On systems where that is not possible, these fixed width types are not provided.






    share|improve this answer


























    • Just to be absolutely clear. Is your last paragraph is a direct counter example against 2nd unanswered question? I am asking from a compound type perspective, so for example struct S {char a,b,c;}; if padded to 4*sizeof(char) could have padding at the end. And for that matter we cannot tell relative address of any member other than a, I think they can be reordered an padded as compiler see fit. Yup?

      – luk32
      13 hours ago













    • @luk32 There cannot possibly be a need for padding between char elements, as they have alignment of 1. Any sensible ABI would place the padding (if there is any) of S at the end. But indeed, I don't know of explicit guarantee about that in the C++ standard.

      – eerorika
      12 hours ago













    • Could you, please, elaborate on this usage of std::launder?

      – lisyarus
      9 hours ago











    • @lisyarus en.cppreference.com/w/cpp/utility/launder

      – eerorika
      9 hours ago











    • @eerorika I apologize, but I struggle to understand the reason why std::launder is needed here based on the cppreference article.

      – lisyarus
      9 hours ago














    9












    9








    9







    One thing that is not guaranteed about the layout is endianness i.e. the order of bytes within a multi-byte object. write_bytes(&x, sizeof(A)) is not portable serialisation across systems with different endianness.




    A can be reinterpret_cast to a pointer to its first data member (which is, presumably, data[0] ?)




    Correction: The first data member is data, which you can reinterpret cast with. And crucially, an array is not pointer-interconvertible with its first element, so you cannot reinterpret cast between them. The address however is guaranteed to be the same, so reinterpreting as data[0] should be fine after std::launder as far as I understand.




    There is no padding in between elements of an array of primitive type




    Arrays are guaranteed to be contiguous. sizeof of an object is specified in terms of padding required to place elements into an array. sizeof(T[10]) has exactly the size sizeof(T * 10). If there is padding between non-padding bits of adjacent elements, then that padding is at the end of the element itself.



    Primitive type is not guaranteed to not have padding in general. For example, the x86 extended precision long double is 80 bits, padded to 128 bits.



    char, signed char and unsigned char are guaranteed to not have padding bits. C standard (to which C++ delegates the specification in this case) guarantees that the fixed width intN_t and uintN_t aliases do not have padding bits. On systems where that is not possible, these fixed width types are not provided.






    share|improve this answer















    One thing that is not guaranteed about the layout is endianness i.e. the order of bytes within a multi-byte object. write_bytes(&x, sizeof(A)) is not portable serialisation across systems with different endianness.




    A can be reinterpret_cast to a pointer to its first data member (which is, presumably, data[0] ?)




    Correction: The first data member is data, which you can reinterpret cast with. And crucially, an array is not pointer-interconvertible with its first element, so you cannot reinterpret cast between them. The address however is guaranteed to be the same, so reinterpreting as data[0] should be fine after std::launder as far as I understand.




    There is no padding in between elements of an array of primitive type




    Arrays are guaranteed to be contiguous. sizeof of an object is specified in terms of padding required to place elements into an array. sizeof(T[10]) has exactly the size sizeof(T * 10). If there is padding between non-padding bits of adjacent elements, then that padding is at the end of the element itself.



    Primitive type is not guaranteed to not have padding in general. For example, the x86 extended precision long double is 80 bits, padded to 128 bits.



    char, signed char and unsigned char are guaranteed to not have padding bits. C standard (to which C++ delegates the specification in this case) guarantees that the fixed width intN_t and uintN_t aliases do not have padding bits. On systems where that is not possible, these fixed width types are not provided.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited 12 hours ago

























    answered 13 hours ago









    eerorikaeerorika

    90k664136




    90k664136













    • Just to be absolutely clear. Is your last paragraph is a direct counter example against 2nd unanswered question? I am asking from a compound type perspective, so for example struct S {char a,b,c;}; if padded to 4*sizeof(char) could have padding at the end. And for that matter we cannot tell relative address of any member other than a, I think they can be reordered an padded as compiler see fit. Yup?

      – luk32
      13 hours ago













    • @luk32 There cannot possibly be a need for padding between char elements, as they have alignment of 1. Any sensible ABI would place the padding (if there is any) of S at the end. But indeed, I don't know of explicit guarantee about that in the C++ standard.

      – eerorika
      12 hours ago













    • Could you, please, elaborate on this usage of std::launder?

      – lisyarus
      9 hours ago











    • @lisyarus en.cppreference.com/w/cpp/utility/launder

      – eerorika
      9 hours ago











    • @eerorika I apologize, but I struggle to understand the reason why std::launder is needed here based on the cppreference article.

      – lisyarus
      9 hours ago



















    • Just to be absolutely clear. Is your last paragraph is a direct counter example against 2nd unanswered question? I am asking from a compound type perspective, so for example struct S {char a,b,c;}; if padded to 4*sizeof(char) could have padding at the end. And for that matter we cannot tell relative address of any member other than a, I think they can be reordered an padded as compiler see fit. Yup?

      – luk32
      13 hours ago













    • @luk32 There cannot possibly be a need for padding between char elements, as they have alignment of 1. Any sensible ABI would place the padding (if there is any) of S at the end. But indeed, I don't know of explicit guarantee about that in the C++ standard.

      – eerorika
      12 hours ago













    • Could you, please, elaborate on this usage of std::launder?

      – lisyarus
      9 hours ago











    • @lisyarus en.cppreference.com/w/cpp/utility/launder

      – eerorika
      9 hours ago











    • @eerorika I apologize, but I struggle to understand the reason why std::launder is needed here based on the cppreference article.

      – lisyarus
      9 hours ago

















    Just to be absolutely clear. Is your last paragraph is a direct counter example against 2nd unanswered question? I am asking from a compound type perspective, so for example struct S {char a,b,c;}; if padded to 4*sizeof(char) could have padding at the end. And for that matter we cannot tell relative address of any member other than a, I think they can be reordered an padded as compiler see fit. Yup?

    – luk32
    13 hours ago







    Just to be absolutely clear. Is your last paragraph is a direct counter example against 2nd unanswered question? I am asking from a compound type perspective, so for example struct S {char a,b,c;}; if padded to 4*sizeof(char) could have padding at the end. And for that matter we cannot tell relative address of any member other than a, I think they can be reordered an padded as compiler see fit. Yup?

    – luk32
    13 hours ago















    @luk32 There cannot possibly be a need for padding between char elements, as they have alignment of 1. Any sensible ABI would place the padding (if there is any) of S at the end. But indeed, I don't know of explicit guarantee about that in the C++ standard.

    – eerorika
    12 hours ago







    @luk32 There cannot possibly be a need for padding between char elements, as they have alignment of 1. Any sensible ABI would place the padding (if there is any) of S at the end. But indeed, I don't know of explicit guarantee about that in the C++ standard.

    – eerorika
    12 hours ago















    Could you, please, elaborate on this usage of std::launder?

    – lisyarus
    9 hours ago





    Could you, please, elaborate on this usage of std::launder?

    – lisyarus
    9 hours ago













    @lisyarus en.cppreference.com/w/cpp/utility/launder

    – eerorika
    9 hours ago





    @lisyarus en.cppreference.com/w/cpp/utility/launder

    – eerorika
    9 hours ago













    @eerorika I apologize, but I struggle to understand the reason why std::launder is needed here based on the cppreference article.

    – lisyarus
    9 hours ago





    @eerorika I apologize, but I struggle to understand the reason why std::launder is needed here based on the cppreference article.

    – lisyarus
    9 hours ago













    2















    If a standard-layout class object has any non-static data members, its
    address is the same as the address of its first non-static data member.
    Otherwise, its address is the same as the address of its first base
    class subobject (if any). [Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. — end note]




    Hence, the standard guarantees that



    static_assert(offsetof(A, data[0]) == 0 * sizeof(float));



    An object of array type contains a contiguously allocated non-empty
    set of N subobjects of type T.




    Hence, the following are true



    static_assert(offsetof(A, data[0]) == 0 * sizeof(float));
    static_assert(offsetof(A, data[1]) == 1 * sizeof(float));
    ...
    static_assert(offsetof(A, data[15]) == 15 * sizeof(float));





    share|improve this answer






























      2















      If a standard-layout class object has any non-static data members, its
      address is the same as the address of its first non-static data member.
      Otherwise, its address is the same as the address of its first base
      class subobject (if any). [Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. — end note]




      Hence, the standard guarantees that



      static_assert(offsetof(A, data[0]) == 0 * sizeof(float));



      An object of array type contains a contiguously allocated non-empty
      set of N subobjects of type T.




      Hence, the following are true



      static_assert(offsetof(A, data[0]) == 0 * sizeof(float));
      static_assert(offsetof(A, data[1]) == 1 * sizeof(float));
      ...
      static_assert(offsetof(A, data[15]) == 15 * sizeof(float));





      share|improve this answer




























        2












        2








        2








        If a standard-layout class object has any non-static data members, its
        address is the same as the address of its first non-static data member.
        Otherwise, its address is the same as the address of its first base
        class subobject (if any). [Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. — end note]




        Hence, the standard guarantees that



        static_assert(offsetof(A, data[0]) == 0 * sizeof(float));



        An object of array type contains a contiguously allocated non-empty
        set of N subobjects of type T.




        Hence, the following are true



        static_assert(offsetof(A, data[0]) == 0 * sizeof(float));
        static_assert(offsetof(A, data[1]) == 1 * sizeof(float));
        ...
        static_assert(offsetof(A, data[15]) == 15 * sizeof(float));





        share|improve this answer
















        If a standard-layout class object has any non-static data members, its
        address is the same as the address of its first non-static data member.
        Otherwise, its address is the same as the address of its first base
        class subobject (if any). [Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. — end note]




        Hence, the standard guarantees that



        static_assert(offsetof(A, data[0]) == 0 * sizeof(float));



        An object of array type contains a contiguously allocated non-empty
        set of N subobjects of type T.




        Hence, the following are true



        static_assert(offsetof(A, data[0]) == 0 * sizeof(float));
        static_assert(offsetof(A, data[1]) == 1 * sizeof(float));
        ...
        static_assert(offsetof(A, data[15]) == 15 * sizeof(float));






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 12 hours ago

























        answered 13 hours ago









        YashasYashas

        7111726




        7111726






























            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%2f55650798%2fguaranteed-memory-layout-for-standard-layout-struct-with-a-single-array-member-o%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

            Wolfgang Unzicker

            Unua mondmilito

            Schloss Hohenburg (Lenggries)