Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Struct offsets and pointer safety in C++

This question is about pointers derived using pointer arithmetic with struct offsets.

Consider the following program:

#include <cstddef>
#include <iostream>
#include <new>

struct A {
  float a;
  double b;
  int c;
};

static constexpr auto off_c = offsetof(A, c);

int main() {
  A * a = new A{0.0f, 0.0, 5};
  char * a_storage = reinterpret_cast<char *>(a);
  int * c = reinterpret_cast<int *>(a_storage + off_c));

  std::cout << *c << std::endl;

  delete a;
}

This program appears to work and give expected results on compilers that I tested, using default settings and C++11 standard.

(A closely related program, where we use void * instead of char * and static_cast instead of reinterpret_cast, is not universally accepted. gcc 5.4 issues a warning about pointer arithmetic with void pointers, and clang 6.0 says that pointer arithmetic with void * is an error.)

Does this program have well-defined behavior according to the C++ standard?

Does the answer depend on whether the implementation has relaxed or strict pointer safety ([basic.stc.dynamic.safety])?

like image 773
Chris Beck Avatar asked Sep 08 '17 20:09

Chris Beck


1 Answers

There are no fundamental errors in your code.

If A isn't plain old data, the above is UB (prior to C++17) and conditionally supported (after C++17).

You might want to replace char* and int* with auto*, but that is a style thing.

Note that pointers to members do this exact same thing in a type-safe manner. Most compilers implement a pointer to member ... as the offset of the member in the type. They do, however, work everywhere even on non-pod structures.

Aside: I don't see a guarantee that offsetof is constexpr in the standard. ;)

In any case, replace:

static constexpr auto off_c = offsetof(A, c);

with

static constexpr auto off_c = &A::c;

and

  auto* a_storage = static_cast<char *>(a);
  auto* c = reinterpret_cast<int *>(a_storage + off_c));

with

  auto* c = &(a->*off_c);

to do it the C++ way.

like image 199
Yakk - Adam Nevraumont Avatar answered Sep 24 '22 19:09

Yakk - Adam Nevraumont