• Indexing a pointer to members of a standard layout type.

    From Edward Rosten@21:1/5 to All on Wed Mar 16 01:06:43 2016
    Hi,

    I've been trying to wrangle the standardese on a bit of code with no
    success. For further background, there's my post about it here:

    https://deathandthepenguinblog.wordpress.com/2016/01/19/apparently-this- is-legal/

    and a discussion I started here:

    https://www.reddit.com/r/cpp/comments/42cbd2/ i_think_pointer_arithmetic_on_struct_members_is/

    Take the following code:

    ////////////////////////////////////////////////
    struct RGB
    {
    float r, g, b;

    float& operator[](int i)
    {
    return (&r + i);
    }
    };
    static_assert(sizeof(RGB) == sizeof(float*3)); ///////////////////////////////////////////////

    So, 9.2/13 says that r, g, b must be in increasing address order. 9.2/19
    says there can be padding so the result is implementation defined.
    However due to the static assert the static_assert it won't compile
    unless the implementation defines it how we want. 3.10/10 doesn't forbid
    it in terms of alisasing since we're accessing a float
    via a float*.

    5.7 might forbid it but only partly. 5.7/4 says r is equivalent to an
    array of length 1, and 5.7/5 says that &r and &r+1 are valid and shall
    not overflow, but &r+2 is undefined. That appears to allow the indexing
    to work, but only for the first two elements.

    Alternatively,

    RGB rgb;
    int i;
    //...
    *(reinterpret_cast<char*>(&rgb.r)+i);

    appears to be valid for i < sizeof(rgb), though I'm not sure I could
    quote the exact section allowing this. Given that the only reason the
    code above might be undefined is due to overflow, I cannot find any
    standardese that forbids the following:

    *reinterpret_cast<float*>(reinterpret_cast<char*>(&rgb.r) +
    sizeof(float)*i)

    To (de) muddy the waters further, an alternative was suggested:

    struct RGB
    {
    union
    {
    struct
    {
    float r, g, b;
    };
    float my_data[3];
    };

    float& operator[](int i)
    {
    return my_data[i];
    }
    };

    Naturally alternating between r and my_data will involve accessing a
    non-active member of the union. As far as I can tell the C++ standard
    simply has nothing to say about that (it is neither explicitly allowed
    nor explicitly forbidden), though the C standard does specify. Is there anything in the standard that specifies what one should assume when the standard is silent on a matter?

    Can anyone shed any light on this? I've dug around but have hit a bit of
    a wall determining if it definitely allowed or definitely disallowed by
    the standard. Have I missed any relavent sections?

    Regards

    -Ed



    --
    [ comp.std.c++ is moderated. To submit articles, try posting with your ]
    [ newsreader. If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
    [ --- Please see the FAQ before posting. --- ]
    [ FAQ: http://www.comeaucomputing.com/csc/faq.html ]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)