typedef struct foo
{
void (*const t)(struct foo *f);
} foo;
void t(struct foo *f)
{
}
void (*const myt)(struct foo *f) = t;
foo f = {.t = t};
int main(void)
{
f.t(&f);
myt(&f);
return 0;
}
使用 x86-64 gcc 13.2 和 clang 16.0.0 编译上述代码时,会生成类似的汇编代码。下面显示的是 gcc 输出。
t:
ret
main:
sub rsp, 8
mov edi, OFFSET FLAT:f
call [QWORD PTR f[rip]]
xor eax, eax
add rsp, 8
ret
f:
.quad t
myt:
.quad t
为什么两个编译器在通过
t
调用时都会发出对 struct foo
函数的调用,而在通过 myt
函数指针调用时却不会?为什么编译器无法看到 t
中的 struct foo
函数指针指向空函数并消除所有调用?由于 f
是静态分配的,并在编译时初始化,因此它的成员 t
(一个在运行时无法更改的常量指针(不调用未定义的行为))指向一个空函数 t
。
由于
f
不是 const 限定的 complete 对象 (cf. [basic.life]/10),它可以被销毁并通过放置 new 重新创建,另一个翻译单元可能会在初始化程序之前执行此操作main
开始。这不仅对于 myt
来说是不可能的,而且它甚至具有内部链接,因此其他翻译单元根本无法引用它。