3

我正在将用 C 编写的第 3 方库 API 翻译成 D。该库导出了许多名为 like 等的函数libname_foofunclibname_barfunc这对于 C 库来说是可以预期的,以防止全局命名空间膨胀。由于 D 比 C 更模块化,我想提供更多的 D'ish 接口并摆脱函数前缀,所以函数看起来像libname.c.foofuncand libname.c.barfunc

由于图书馆不知道我的“改进”,我必须以某种方式同时翻译libname.c.foofunclibname_foofunc保留正确的外部链接、目标名称修改和调用约定。

假设有办法(我也不知道)告诉链接器外部未解析符号__imp__D1c7foofuncFZi对应于_libname_foofuncor libname_foofunc@0(尽管我必须手动进行名称修改),告诉 D 调用约定是什么仍然存在问题。

extern(C) int foofunc()如果我在 中明确指定libname/c.di,则不再存在调用约定问题,但名称被转换为_foofunc,这也与预期不同。

那么,D 中是否有办法以与导出名称不同的名称导入外部函数?

我已经考虑过以原始名称“按原样”导入函数,然后将它们别名为无前缀的类似物,但这似乎很笨拙。

4

4 回答 4

3

您可以使用

alias libname_foofunc foofunc;

这将保持libname_foofunc可见,但允许您使用foofunc,编译器会将其转换为libname_foofunc

于 2012-04-05T14:16:18.527 回答
2

考虑到旧约的最后一段,答案是否定的。没有其他语言可以做到这一点,你描述的方式,它不应该。如果 API 设计者想要以您喜欢的方式命名函数,他们会以这种方式公开它们......

现在想象一下 A 组的开发人员更喜欢some_function(),然后 B 组更喜欢someFunction(),C 组更喜欢SomeFunction()......

别名是必须的,无论你使用 D 还是其他东西。它应该是这样的。API 应该简单、简洁、易于理解。

于 2012-04-05T15:44:54.337 回答
2

就链接而言,符号实际上是 C 的东西,因为我们正在谈论 C 链接器。D 在链接和导出符号方面的情况与在 C++ 中的情况基本相同,这就是为什么会出现名称错误之类的原因。您将不得不使用它们的原始名称在 D 中为它们创建声明,因为这是链接器所期望的。D 没有做任何不同或神奇的事情来改变这一点。只有两种方法可以使用不同的名称。

  1. 给你的 D 代码中的函数起别名。您可以将别名放在列出符号的任何模块中(因为无论如何您都必须在 D 中声明它们)。然后您的代码可以使用原始名称或别名。我没有看到任何笨拙的地方。

  2. 创建包装函数 - 在 C 或 D 中 - 并让您的 D 代码使用它们。

别名肯定会更好恕我直言。它们不会引入任何开销并且不太复杂。

但无论如何,在 D 中使用 C 库时,正常的做法就是使用 C 函数名称。你正在调用 C 函数,这个事实不应该被隐藏。它们不是 D 函数,并且行为不同(即使它们相似)——尤其是在涉及到谁拥有你传递给函数的内存之类的东西时。重命名它们的好处是有争议的。通常是在编写 D 包装器以赋予 API 更清洁、更像 D 的 API(而不仅仅是更改名称)时,不再直接使用 C 函数。在 Phobos 中一个很好的例子是 etc.c.curl 与 std.net.curl。etc.c.curl 纯粹是 C API,不会尝试重命名任何内容。它不会创建任何别名来使符号匹配 Phobos 的命名约定或使它们更像 D。它' s 本质上只是 curl 头文件的 D 版本。另一方面,std.net.curl 建立在它之上,以提供更像 D 的 API 和抽象。它所做的远不止重命名 C 函数。

于 2012-04-05T17:00:53.693 回答
1

如果您不想将函数放入模块中,则可以将它们保存在结构中并模拟某种名称空间。例如,您可以这样做:

struct libname
{
    struct C
    {
        static int libname_foofunc();
        alias libname_foofunc foofunc;
    }

    static C c;
}

void main()
{
    libname.c.foofunc();
}
于 2012-04-05T18:46:29.023 回答