Consider the following C program (which is based on an example from this article):
#include <stdio.h>
short g(int *p, short *q) {
short z = *q; *p = 10; return z;
}
int main(void) {
union int_or_short { int x; short y; } u = { .y = 3 };
int *p = &u.x;
short *q = &u.y;
short r = g(p, q);
printf("%hd %d\n", r, u.x);
}
Does this program exhibit undefined behavior? Please explain by referring to specific passages in the C17 Standard.
This is in fact undefined behavior, as the union definition is not visible in the function g and therefore the compiler may assume that the p and q parameters (which point to incompatible types) point to distinct objects.
There's a nearly identical example given in section 6.5.2.3p9:
EXAMPLE 3 The following is a valid fragment:
union { struct { int alltypes; } n; struct { int type; int intnode; } ni; struct { int type; double doublenode; } nf; } u; u.nf.type = 1; u.nf.doublenode = 3.14; /* ... */ if (u.n.alltypes == 1) if (sin(u.nf.doublenode) == 0.0) /* ... */The following is not a valid fragment (because the union type is not visible within function f):
struct t1 { int m; }; struct t2 { int m; }; int f(struct t1 *p1, struct t2 *p2) { if (p1->m < 0) p2->m = -p2->m; return p1->m; } int g() { union { struct t1 s1; struct t2 s2; } u; /* ... */ return f(&u.s1, &u.s2); }
The second piece of code above is passing pointers to two members of the same union to a function where the union definition is not visible, followed by 1) a read of one member 2) a write of the other 3) a read of the first, just as in your example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With