我正在尝试使用结构内的函数指针在 C 中实现抽象接口。
类似于下面的内容
typedef int (*fn_t)(int);
typedef struct
{
int x;
const fn_t fnp;
}struct_t;
__attribute__((optimize("O0"))) int square(int num)
{
return num * num;
}
static struct_t test = {.fnp = square};
int main(void)
{
test.x = 1;
int fnp_ret = test.fnp(3);
return (fnp_ret);
}
当使用 ARM-GCC-13.2.0unknown-eabi 使用 -O3 构建 godbolt 时,输出如下。
square:
str fp, [sp, #-4]!
add fp, sp, #0
sub sp, sp, #12
str r0, [fp, #-8]
ldr r3, [fp, #-8]
mov r2, r3
mul r2, r3, r2
mov r3, r2
mov r0, r3
add sp, fp, #0
ldr fp, [sp], #4
bx lr
main:
mov r1, #1
ldr r3, .L5
mov r0, #3
ldr r2, [r3, #4]
str r1, [r3]
bx r2
.L5:
.word .LANCHOR0
在这里可以看到,在发出的程序集中,首先在结构中找到函数指针,然后取消引用它。我觉得这很奇怪,因为函数指针是
main()
所以我希望编译器应该弄清楚它总是指向 const
函数,所以它相当于直接调用 square
函数。显然这里的情况并非如此。在实验过程中,我注意到,如果语句 square
被注释掉,程序集会通过直接调用
test.x = 1;
函数来执行我所期望的操作square
我错过了什么?有没有什么方法可以可靠地实现这一点,而无需支付上述性能损失?
square:
str fp, [sp, #-4]!
add fp, sp, #0
sub sp, sp, #12
str r0, [fp, #-8]
ldr r3, [fp, #-8]
mov r2, r3
mul r2, r3, r2
mov r3, r2
mov r0, r3
add sp, fp, #0
ldr fp, [sp], #4
bx lr
main:
mov r0, #3
b square
noinline
const
恐怕你对此无能为力