2

If I have a union

union U {
  int i;
  double d;
};

Then I can get pointers to an object's members as

U u;
int *ip = &u.i;
double *dp = &u.d;

and as I read the standard

C11, 6.7.2.1 §16: The size of a union is sufficient to contain the largest of its members. The value of at most one of the members can be stored in a union object at any time. A pointer to a union object, suitably converted, points to each of its members (or if a member is a bitfield, then to the unit in which it resides), and vice versa.

also as

U u;
int *ip = (int *)&u;
double *dp = (double *)&u;

Is this a correct reading?

If so, does

C11, 6.3.2.3 § 7 A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer. When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object.

allow me to also do this?

int *ip2 = (int *)dp;
double *dp2 = (double *)ip;

If the union sits aligned so it can contain its members, then it must be aligned to both int and double, so there is no problem there, but I can also read the standard as talking about the pointer being correctly aligned, not the object it points to.

I suppose that the first paragraph doesn't say that I can convert the member pointers back to the union

U *up1 = (union U *)ip;
U *up2 = (union U *)dp;

so I guess that I am not guaranteed that this would give me up1 == up2? So I wouldn't even be guaranteed that I could write this ugly code and be standard compliant.

int *ip2 = (int *)((union U *)dp);
double *dp2 = (double *)((union U *)ip);

That is, unless the second paragraph says that because I made a cast from the union to the other types, that were correctly aligned, then I would get the correct pointer back. But I am not sure that I can interpret it that way, for the same reason that I am not sure that I can cast between the pointers to members.

Am I allowed to cast a pointer to a union to a pointer of the type of one of its members? And am I then allowed to cast that pointer to one with the type of another member?

I am not going to do something particularly crazy with this knowledge, I just got wondering when I read the standard for a slightly less idiotic case...

Thomas Mailund
  • 1,674
  • 10
  • 16
  • 1
    Least to say, complex topic. Have you seen this: https://stackoverflow.com/questions/25664848/unions-and-type-punning ? – alagner Oct 01 '20 at 06:57
  • 2
    Re “I suppose that the first paragraph doesn't say that I can convert the member pointers back to the union”: That supposition is incorrect. The passage you quoted says a pointer to a union, suitably converted, points to each of its members **and vice-versa**. – Eric Postpischil Oct 01 '20 at 07:50

0 Answers0