Guilherme Bernal
Guilherme Bernal

Reputation: 8293

Is a struct of one element compatible with the element itself?

If I have the following struct:

struct Foo { int a; };

Is the code bellow conforming with the C++ Standard? I mean, can't it generate an "Undefined Behavior"?

Foo foo;
int ifoo;

foo = *reinterpret_cast<Foo*>(&ifoo);

void bar(int value);

bar(*reinterpret_cast<int*>(&foo));

auto fptr = static_cast<void(*)(...)>(&bar);
fptr(foo);

Upvotes: 6

Views: 304

Answers (3)

s3rius
s3rius

Reputation: 1452

Foo is a plain-old-data structure, which means it contains nothing but the data you explicitely store in it. In this case: an int. Thus the memory layout for an int and Foo are the same.

You can typecast from one to the other without problems. Whether it's a clever idea to use this kind of stuff is a different question.

PS: This usually works, but not necessarily due to different alignment restrictions. See AProgrammer's answer.

Upvotes: 2

AProgrammer
AProgrammer

Reputation: 52284

9.2/20 in N3290 says

A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa.

And your Foo is a standard-layout class.

So your second cast is correct.

I see no guarantee that the first one is correct (and I've used architecture where a char had weaker alignment restriction than a struct containing just a char, on such an architecture, it would be problematic). What the standard guarantee is that if you have a pointer to int which really point to the first element of a struct, you can reinterpret_cast it back to pointer to the struct.

Likewise, I see nothing which would make your third one defined if it was a reinterpret_cast (I'm pretty sure that some ABI use different convention to pass structs and basic types, so it is highly suspicious and I'd need a clear mention in the standard to accept it) and I'm quite sure that nothing allow static_cast between pointers to functions.

Upvotes: 10

user529758
user529758

Reputation:

As long as you access only the first element of a struct, it's considered to be safe, since there's no padding before the first member of a struct. In fact, this trick is used, for example, in the Objecive-C runtime, where a generic pointer type is defined as:

typedef struct objc_object {
    Class isa;
} *id;

and in runtime, real objecs (which are still bare struct pointers) have memory layouts like this:

struct {
    Class isa;
    int x; // random other data as instance variables
} *CustomObject;

and the runtime accesses the class of an actual object using this method.

Upvotes: 4

Related Questions