https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63645
--- Comment #16 from Markus Trippelsdorf <trippels at gcc dot gnu.org> --- (In reply to M Welinder from comment #14) > > 2) In the if statement, where you probe the different members, you > > also invoke undefined behavior. > > Absolutely not! I went other that in painful detail in comment 8. > Bottom line: only one member is accessed. Let's take this example: markus@x4 tmp % cat union.c #include <stdlib.h> typedef union _GnmExpr GnmExpr; typedef char GnmFunc; typedef unsigned char guint8; typedef enum { GNM_EXPR_OP_LT, GNM_EXPR_OP_FUNCALL } GnmExprOp; typedef struct { guint8 oper; int argc; GnmFunc *func; } GnmExprFunction; typedef struct { guint8 oper; } GnmExprBinary; union _GnmExpr { GnmExprFunction func; GnmExprBinary binary; }; int main (void) { GnmExprBinary res; res.oper = GNM_EXPR_OP_LT; GnmExpr const *expr = (GnmExpr *)&res; if (expr->binary.oper == GNM_EXPR_OP_FUNCALL && expr->func.argc == 1 && expr->func.func == getenv ("NOT")) abort (); return 0; } Here the compiler even warns: markus@x4 tmp % gcc -Wall -Wextra -g -O2 union.c union.c: In function ‘main’: union.c:40:7: warning: ‘res.func.func’ may be used uninitialized in this function [-Wmaybe-uninitialized] && expr->func.func == getenv ("NOT")) ^ And that is because the compiler assumes that no undefined behavior happens and optimizes accordingly. The gcc documentation even mentions this case explicitly (under -fstrict-aliasing): »Similarly, access by taking the address, casting the resulting pointer and dereferencing the result has undefined behavior, even if the cast uses a union type.«