为共享库中的各种函数签名提供兼容性

  • 本文关键字:兼容性 函数 共享 c
  • 更新时间 :
  • 英文 :


我正在使用Python的C扩展,该扩展动态加载第三方库并调用其函数。有一次,第三方将他们的一个函数签名从foo(int a, int b)更改为foo(int a),我正在努力解决如何提供兼容层的问题。

在Python中,我可以检查第三方库的版本,并将其传递给C函数。在那里,我试着像一样进行分支

if (version >= 1) {
foo(42);
} else {
foo(42, 42);
}

同时还提供类似void foo(int a, ...)的声明

这在运行时编译但segfault,可能是因为为可变参数分配的空间与额外参数不同。

我也尝试过使用foo(int a)的更新声明,但在编译阶段仍然会生成too few arguments to 'foo'。旧的定义在这里也不起作用。

有什么策略可以让我在运行时编译并执行正确的行为吗?

您可以用一种类型声明函数,并且在调用另一种类型时,将其地址转换为指向函数实际定义的类型的指针:

void foo(int a, int b);
void bar(int version)
{
if (version >= 1) {
((void (*)(int)) &foo)(42);
} else {
foo(42, 42);
}
}

我已经显式地展示了&,以表明我们正在获取一个指向函数的指针,将其转换为指向不同类型的指针,并使用转换后的指针来调用该函数。但是,您可以省略&,因为函数(如数组(会在需要时自动转换为指针。

这包括在调用函数时,函数调用操作实际上采用指针,而不是函数指示符。由于自动转换,cos(x)实际上是(&cos)(x)。这就是为什么我们在进行函数调用时不需要将*与上面的指针一起使用。

这稍微推动了C标准定义的行为,但在典型的C实现中应该是可以的。定义了函数指针到其他类型函数指针的转换,当然也定义了用实际定义的类型调用函数。值得怀疑的是,这个函数将在void foo(int a, int b);中用一种类型声明,尽管它的实际定义是另一种类型。然而,由于C编译器看不到实际的定义,因此编译器的行为不会受到影响。只有在使用不同表示形式作为指向不同类型函数的指针的奇异C实现中才会出现问题,这可能会导致链接器为声明的foo提供的表示形式与编译器预期的不同。

最新更新