我正在将用C编写的第三方库API转换为D.该库导出了许多名为libname_foofunc
,libname_barfunc
等的函数,这对C库来说可以防止膨胀全局命名空间。由于D比C更模块化,我想提供更多D'ish接口并摆脱函数前缀,因此函数看起来像libname.c.foofunc
和libname.c.barfunc
。
由于库不知道我的“改进”,我必须以某种方式将libname.c.foofunc
转换为libname_foofunc
并保留正确的外部链接,目标名称修改和同时调用约定。
假设有方法(我也不知道)告诉链接器外部未解析的符号__imp__D1c7foofuncFZi
对应_libname_foofunc
或libname_foofunc@0
(尽管我必须做名字)手工碾磨),仍然有问题告诉D什么是召唤惯例。
如果我在extern(C) int foofunc()
中明确指定libname/c.di
,则不再存在调用约定问题,但名称会转换为_foofunc
,这也与预期不同。
那么,在D中导入外来函数的方式是否与导出的名称不同?
我虽然在原始名称下“按原样”导入功能,然后将它们别名为无前缀的类似物,但这似乎非常笨拙。
答案 0 :(得分:3)
你可以使用
alias libname_foofunc foofunc;
这会使libname_foofunc
可见,但允许您使用foofunc
,编译器会将其转换为libname_foofunc
答案 1 :(得分:2)
考虑到旧约的最后一段,答案是否定的。没有其他语言能够像你描述的那样去做,也不应该这样做。如果API设计者希望以您喜欢的方式拥有函数名称,那么他们会以这种方式公开它们......
现在想象一下那些喜欢some_function()
,然后B组喜欢someFunction()
的开发者的A组和喜欢SomeFunction()
的C组......
无论你使用D还是其他东西,别名都是必须的。它应该是那样的。 API应该简单,简洁,易于理解。
答案 2 :(得分:2)
就链接而言,符号实际上是C的东西,因为我们讨论的是C链接器。 D与链接和导出符号的情况基本上与C ++中的情况相同,这就是为什么有错误的名称等。您将不得不使用其原始名称在D中为它们创建声明,因为这是链接器所期望的。 D没有做任何不同或神奇的事情会改变这一点。只有两种方法可以使用不同的名称。
为D代码中的函数添加别名。您可以将别名放在任何模块中列出符号(因为您必须在D中声明它们)。然后您的代码可以使用原始名称或别名。我没有看到任何笨拙的事情。
创建包装函数 - 使用C或D - 并让D代码使用它们。
别名肯定会更好恕我直言。它们不会引入任何开销,也不那么复杂。
但无论如何,从D使用C库时,正常的做法就是使用C函数名。你正在调用C函数,不应该隐藏这个事实。它们不是D函数,并且不是相同的(即使它们是相似的) - 特别是当涉及到拥有你传递给函数的内存的东西时。重命名它们的好处值得商榷。通常在编写D包装器时,为API提供更清晰,更像D的API(而不仅仅是更改名称),不再直接使用C函数。 Phobos的一个很好的例子是etc.curl vs std.net.curl。 etc.c.curl纯粹是C API,不会尝试重命名任何东西。它不会创建任何别名来使符号与Phobos的命名约定相匹配或使它们更像D。它本质上只是curl头文件的D版本。另一方面,std.net.curl构建在它之上,以提供更像D的API和抽象。它远不止重命名C函数。
答案 3 :(得分:1)
如果您不想将这些函数放入模块中,可以将它们保存在结构体中并模拟某种命名空间。例如。你可以这样做:
struct libname
{
struct C
{
static int libname_foofunc();
alias libname_foofunc foofunc;
}
static C c;
}
void main()
{
libname.c.foofunc();
}