Is using type-punning for converting between objects of the same type defined by the C standard?

91 Views Asked by At

In "Structure and union members" part of the C standard, an analogue of the following code is mentioned to be valid: (ISO/IEC 9899:201x, 6.5.2.3.9 EXAMPLE 3)

#include<stdio.h>

union point {
  struct {
    int value;
  } x;
  struct {
    int value;
  } y;
};

int main() {
  union point p;
  p.x.value = 1;
  printf("%d\n", p.y.value);
}

That's because of the following section of the draft:

One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. Tw o structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members.

Is this also valid according to the standard?

#include<stdio.h>

union point {
  int x;
  int y;
};

int main() {
  union point p;
  p.x = 1;
  printf("%d\n", p.y);
}

Is there some sort of paragraph in the specification that guarantees the object representation is fully dependent on the type of the object and thus this is fine?

Would it also work with more complex types? (like structs or unions?)

To extend the question, given:

union first {
  int a;
  char b;
};

union second {
  int a; 
  char b;
  float c;
};

Is there any way to write a pure function with the signature:

union second convert(union first input)

that follows the standard and doesn't require us to remember which variant is stored in union first and which maps the matching union first member onto the union second members?

1

There are 1 best solutions below

1
Eric Postpischil On

Is using type-punning for converting between objects of the same type defined by the C standard?

Accessing an object as the type that it is is not type punning.

Given union point { int x; int y; }; and union point p;, if a value is stored in p.x and then accessed with p.y, the value is that of p.y, per C 2018 6.5.2.3 3. Note 99 makes it clear that the value of p.y is the value represented by the bytes in the union interpreted as the type of p.y:

If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called "type punning"). This might be a trap representation.

Since the bytes in the union are those that were used to store a value in p.x, of type int, then when interpreted as type int for p.y, they represent the same value.

is there some sort of paragraph in the specification that guarantees the object representation is fully dependent on the type and thus this is fine?

C 2018 6.2.6 specifies how types are represented, and paragraph 2 says:

Except for bit-fields, objects are composed of contiguous sequences of one or more bytes, the number, order, and encoding of which are either explicitly specified or implementation-defined.

To extend the question, is there any way to convert union first object to union second that follows the standard and doesn't require us to remember which variant is stored in union first:

union first {
  int a;
  char b;
};

union second {
  int a; 
  char b;
  float c;
};

It is not clear what you mean here. If you have some object that is a union first, then it is a union first. Objects are regions of memory whose contents may represent values. C accesses objects (for writing or reading), and it operates on values. There is no operation to convert an object to another object. Values can be converted. Objects can be interpreted as one type or another. If you have questions about interpreting the region of memory forming one object using another type, you need to be clearer about what you are attempting to do and the circumstances.