我对如何最好地处理公共(public) API 中的调用约定差异并使其与其绑定(bind)保持同步感到有点困惑。假设我正在编写一个 C API,通过共享对象库或 DLL 提供。现在假设我被告知我不应该在 Windows 上使用默认调用约定——也就是说,在 Linux 和其他 Unix 上我应该使用编译器使用的标准调用约定(可能是 cdecl
)但是在Windows 我应该强制使用 stdcall
。所以我在 header 中有一些 #ifdef
逻辑,可以根据需要设置正确的调用约定。库的 C header 必须处理这一点,因此 C 公共(public) API 可用。
现在假设我想用另一种语言为我的库编写绑定(bind)。这意味着我也必须用该语言重写调用约定逻辑(取决于当前系统),以便绑定(bind)正确映射到库。依此类推所有绑定(bind)。某些语言可能对此没有很好的(或任何)支持。
有没有更优雅的方法来做到这一点?我是否应该在任何地方都使用默认调用约定,并假设其他语言会为外部/导入函数选择正确的调用约定?我什至需要担心这些东西吗(我想是的)?谢谢。
最佳答案
许多语言使用内置或第三方库来简化对共享库的调用。这些库通常包括对这两种调用约定的支持。这方面的一个例子是 JNA用于从 java 调用 native 共享库。话虽这么说,如果您不想依赖使用单一调用约定的其他语言,您可以实现包含两种类型函数的共享库,并具有为每种类型返回适当绑定(bind)的初始化程序。例如,如果您的库有 2 个名为 function1
和 function2
的函数,您可以这样实现它:
typedef struct
{
int (*function1)(int a, int b);
char* (*function2)(void);
}API;
//stdcall implementation
//these functions compiled to use stdcalling convention
int stdcall_function1(int a, int b)
{
/*...*/
}
char* stdcall_function2(void)
{
/*...*/
}
API getSTDCallInstance()
{
API api;
api.function1 = &stdcall_function1;
api.function2 = &stdcall_function2;
return api;
}
//cdecl implementation
//these functions compiled to use cdecl convention
int cdecl_function1(int a, int b)
{
/*...*/
}
char* cdecl_function2()
{
/*...*/
}
API getCDECLInstance()
{
API api;
api.function1 = &cdecl_function1;
api.function2 = &cdecl_function2;
return api;
}
如果您以这种方式实现您的库,则加载语言可以使用适当的初始化器来获取包含它们正确实现的结构的句柄。
关于调用约定和语言绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20611840/