Is using offsetof() with pointer arithmetic undefined?

102 views
Skip to first unread message

Myriachan

unread,
May 15, 2015, 7:57:46 PM5/15/15
to std-dis...@isocpp.org
The C++ Standard permits you to use offsetof() on standard-layout classes, but does it permit using that offset in pointer arithmetic with object pointers that have been reinterpret_cast to [unsigned] char *?

The section on pointer arithmetic is predicated on "if the pointer object points to an element of an array object" (§5.7/4), with undefined behavior otherwise.  It has a footnote stating that, "an object that is not an array is considered to belong to a single-element array for this purpose".  But if you reinterpret_cast a pointer to a single object into a char pointer, that's not a pointer to an array object.

Does this mean that doing pointer arithmetic on a reinterpret_cast char pointer of a single object in order to reach other members is undefined behavior even for standard-layout types?  It seems to me that this was not the intention of the Standard.  Getting around this would require using memcpy into a char array, only ever using the offset for indexing into that char array, then copying back.

Another possible interpretation of the Standard is that the reinterpret_cast pointer *does* point to an array.  One way this interpretation could be derived is from §1.8/5: "An object of trivially copyable or standard-layout type (3.9) shall occupy contiguous bytes of storage.".

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <type_traits>

struct Meow
{
   
int x;
   
float y;
};

int main()
{
   
Meow meow;
   
static_assert(std::is_standard_layout<Meow>::value, "Meow isn't standard-layout");

   
// Aliasing rules allow this (3.10/8)
   
unsigned char *p = reinterpret_cast<unsigned char *>(&meow);

   
// Meow is standard-layout, but is this technically undefined behavior?
    p
+= offsetof(Meow, y);

   
float z = std::exp(1.0f);
    std
::memcpy(p, &z, sizeof(float));
   
    std
::printf("%f\n", meow.y);

   
return 0;
}


Melissa

Columbo

unread,
May 16, 2015, 8:13:48 AM5/16/15
to std-dis...@isocpp.org
Am Samstag, 16. Mai 2015 00:57:46 UTC+1 schrieb Myriachan:
The section on pointer arithmetic is predicated on "if the pointer object points to an element of an array object" (§5.7/4), with undefined behavior otherwise.  It has a footnote stating that, "an object that is not an array is considered to belong to a single-element array for this purpose".  But if you reinterpret_cast a pointer to a single object into a char pointer, that's not a pointer to an array object.

I believe this was indirectly covered by CWG 1504.

For addition or subtraction, if the expressions P or Q have type “pointer to cv T”, where T and the array element type are not similar (4.4), the behavior is undefined.


// Aliasing rules allow this (3.10/8)
unsigned char *= reinterpret_cast<unsigned char *>(&meow);

That's allowed by §5.2.10/7. I could cast to a pointer to kitty, if I wanted. 
Reply all
Reply to author
Forward
0 new messages