Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Post History
memcpy(&y.t, &x, sizeof(x)); is a bit fishy since it would have made more sense to copy into &y or &y.s. None of this is necessarily UB however. Regarding strict aliasing, it doesn...
Answer
#3: Post edited
- `memcpy(&y.t, &x, sizeof(x));` is a bit fishy since it would have made more sense to copy into `&y` or `&y.s`. None of this is necessarily UB however.
- Regarding strict aliasing, it doesn't really matter. If you allocate with a `malloc`-like function then the data has no declared type and effective type rules C17 6.7 §6 apply, which covers `memcpy`. Either way the effective type becomes `struct s`, but inside a union that doesn't really matter.
- ---
- More relevant is the rule about union type punning C17 6.5.2.3 §3 (normative) and foot note 97 (informative):
- > 97) 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.
- Here is the only case where UB might kick in - when you read a union member and the data gets reinterpreted as another type and matches a trap representation. Not relevant for 2's complement `int` but could be relevant for pointer members and maybe floating point.
- ---
- Also noteworthy is the oddball rule _common initial sequence_:
- > 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. Two 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.
Since both your structs are present in a translation unit where the `union` is visible - and only then - it is formally well-defined to do this:```cstruct s x = {42, 53};struct t* y = (struct t*)&x;printf("%d", y.a);```- However lots of compilers have a bleak history on non-conformance here, so I wouldn't count on code relying on common initial sequence to be portable, even though the C standard marks it as well-defined.
- `memcpy(&y.t, &x, sizeof(x));` is a bit fishy since it would have made more sense to copy into `&y` or `&y.s`. None of this is necessarily UB however.
- Regarding strict aliasing, it doesn't really matter. If you allocate with a `malloc`-like function then the data has no declared type and effective type rules C17 6.7 §6 apply, which covers `memcpy`. Either way the effective type becomes `struct s`, but inside a union that doesn't really matter.
- ---
- More relevant is the rule about union type punning C17 6.5.2.3 §3 (normative) and foot note 97 (informative):
- > 97) 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.
- Here is the only case where UB might kick in - when you read a union member and the data gets reinterpreted as another type and matches a trap representation. Not relevant for 2's complement `int` but could be relevant for pointer members and maybe floating point.
- ---
- Also noteworthy is the oddball rule _common initial sequence_:
- > 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. Two 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.
- Since both your structs are present in a translation unit where the `union` is visible - and only then - it is formally well-defined to inspect any member in this common initial sequence no matter through which type. In your example s.a and t.a are guaranteed to overlap.
- However lots of compilers have a bleak history on non-conformance here, so I wouldn't count on code relying on common initial sequence to be portable, even though the C standard marks it as well-defined.
#2: Post edited
`memcpy(&y.t, &x, sizeof(x));` is a bit fishy since it would have made more sense to copy into `&y` or `&y.s`. None of this necessarily UB however.- Regarding strict aliasing, it doesn't really matter. If you allocate with a `malloc`-like function then the data has no declared type and effective type rules C17 6.7 §6 apply, which covers `memcpy`. Either way the effective type becomes `struct s`, but inside a union that doesn't really matter.
- ---
- More relevant is the rule about union type punning C17 6.5.2.3 §3 (normative) and foot note 97 (informative):
- > 97) 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.
- Here is the only case where UB might kick in - when you read a union member and the data gets reinterpreted as another type and matches a trap representation. Not relevant for 2's complement `int` but could be relevant for pointer members and maybe floating point.
- ---
- Also noteworthy is the oddball rule _common initial sequence_:
- > 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. Two 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.
- Since both your structs are present in a translation unit where the `union` is visible - and only then - it is formally well-defined to do this:
- ```c
- struct s x = {42, 53};
- struct t* y = (struct t*)&x;
- printf("%d", y.a);
- ```
- However lots of compilers have a bleak history on non-conformance here, so I wouldn't count on code relying on common initial sequence to be portable, even though the C standard marks it as well-defined.
- `memcpy(&y.t, &x, sizeof(x));` is a bit fishy since it would have made more sense to copy into `&y` or `&y.s`. None of this is necessarily UB however.
- Regarding strict aliasing, it doesn't really matter. If you allocate with a `malloc`-like function then the data has no declared type and effective type rules C17 6.7 §6 apply, which covers `memcpy`. Either way the effective type becomes `struct s`, but inside a union that doesn't really matter.
- ---
- More relevant is the rule about union type punning C17 6.5.2.3 §3 (normative) and foot note 97 (informative):
- > 97) 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.
- Here is the only case where UB might kick in - when you read a union member and the data gets reinterpreted as another type and matches a trap representation. Not relevant for 2's complement `int` but could be relevant for pointer members and maybe floating point.
- ---
- Also noteworthy is the oddball rule _common initial sequence_:
- > 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. Two 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.
- Since both your structs are present in a translation unit where the `union` is visible - and only then - it is formally well-defined to do this:
- ```c
- struct s x = {42, 53};
- struct t* y = (struct t*)&x;
- printf("%d", y.a);
- ```
- However lots of compilers have a bleak history on non-conformance here, so I wouldn't count on code relying on common initial sequence to be portable, even though the C standard marks it as well-defined.
#1: Initial revision
`memcpy(&y.t, &x, sizeof(x));` is a bit fishy since it would have made more sense to copy into `&y` or `&y.s`. None of this necessarily UB however. Regarding strict aliasing, it doesn't really matter. If you allocate with a `malloc`-like function then the data has no declared type and effective type rules C17 6.7 §6 apply, which covers `memcpy`. Either way the effective type becomes `struct s`, but inside a union that doesn't really matter. --- More relevant is the rule about union type punning C17 6.5.2.3 §3 (normative) and foot note 97 (informative): > 97) 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. Here is the only case where UB might kick in - when you read a union member and the data gets reinterpreted as another type and matches a trap representation. Not relevant for 2's complement `int` but could be relevant for pointer members and maybe floating point. --- Also noteworthy is the oddball rule _common initial sequence_: > 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. Two 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. Since both your structs are present in a translation unit where the `union` is visible - and only then - it is formally well-defined to do this: ```c struct s x = {42, 53}; struct t* y = (struct t*)&x; printf("%d", y.a); ``` However lots of compilers have a bleak history on non-conformance here, so I wouldn't count on code relying on common initial sequence to be portable, even though the C standard marks it as well-defined.