Groups | Search | Server Info | Keyboard shortcuts | Login | Register


Groups > comp.std.c++ > #785

Indexing a pointer to members of a standard layout type.

Message-ID <nakd9s$6fa$1@dont-email.me> (permalink)
Newsgroups comp.std.c++
From Edward Rosten <firstname.dot.lastname@googlemail.com>
Subject Indexing a pointer to members of a standard layout type.
Organization A noiseless patient Spider
Date 2016-03-16 01:06 -0600

Show all headers | View raw


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                      ]

Back to comp.std.c++ | Previous | Next | Find similar


Thread

Indexing a pointer to members of a standard layout type. Edward Rosten <firstname.dot.lastname@googlemail.com> - 2016-03-16 01:06 -0600

csiph-web