Indexing a pointer to members of a standard layout type.

44 views
Skip to first unread message

Edward Rosten

unread,
Mar 16, 2016, 2:10:10 AM3/16/16
to

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...@vandevoorde.com ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]

Reply all
Reply to author
Forward
0 new messages