根据 ANSI,我怀疑这是 UB,但在我的系统(x64 Linux)上,即使使用
-Wall -Wextra -Werror -O3
,gcc
和 clang
都会在这里产生预期的结果:
#include <stdio.h>
typedef struct {
int tag;
} base;
typedef struct {
base b;
int x;
} derived1;
typedef struct {
base b;
int x, y;
} derived2;
int sum(void* p) {
base* b = (base*)p;
if(b->tag) {
derived2* d = (derived2*)b;
return d->x + d->y;
}
else {
derived1* d = (derived1*)b;
return d->x;
}
}
int main(void) {
derived1 d1;
d1.b.tag = 0;
d1.x = 2;
derived2 d2;
d2.b.tag = 1;
d2.x = 3;
d2.y = 4;
printf("%d %d\n", sum(&d1), sum(&d2));
}
根据 ANSI,这是 UB 吗?
gcc
和clang
也是UB吗?
如果我使用
-fno-strict-aliasing
或其他选项怎么办?
定义该行为是因为 C 2018 6.7.2.1 15 说“...指向结构对象的指针,经过适当转换,指向其初始成员...”因为
sum
传递了指向 derived1
或 derived2
的指针,尽管转换为 void *
,并将其转换为 base *
,它是 derived1
和 derived2
的初始成员,结果是指向该初始成员的正确指针。 (迂腐地说,C 标准没有定义“适当转换”,但接受这个转换序列作为适当转换并没有争议。)