d2:参数存储类与在D外部实现的功能的互操作性

时间:2012-04-06 21:15:29

标签: c interop d

const(和in

考虑有C函数:

unsigned int foo(const unsigned int a);

const对生成的代码没有任何影响,就像代码使用const进行编译一样,如果没有const则不会中断 - 所以C编译器在编译时使用它仅作为代码合同说明者。

在D中调用此函数是否需要编写uint foo(in uint a);uint foo(const uint a);?这可以帮助D编译器生成更有效的代码来调用foo,否则这将无效(至少对于值类型参数)?

refout

有C功能

unsigned int bar(unsigned int *a);

我是否有义务在将其翻译为D时使用指针语法uint bar(uint* a);,或者我可以写uint bar(ref uint a);(或uint bar(out uint a);,如果我知道a仅适用于输出,来自bar的文档?在refout下是否还有其他隐藏的机制,或者它们似乎只是简单的指针?当D调用超出D范围时,D会生成“粘合代码”以将out参数初始化为默认值吗?

Update1:​​我编写了简单的代码来测试refout在参数中的处理方式 - 它们实际上似乎只是{{{ 1}} s,但int在传递时不会重置为初始值 - C端仍然可以读取它的值并对其进行修改,因此它有效地像out一样运行。我不确定,当我以这种方式使用东西时,我是否应该期待与GC相关的问题。

Update2:在功能结果中使用ref代替指针也是预期的方式。 ref仍未经过测试,我不知道如何检查它而无需反汇编程序。

2 个答案:

答案 0 :(得分:1)

由于C不会破坏参数,因此将与任何类型限定符链接。

程序员应该确保在extern(C)函数原型中声明的D类型限定符实际上与C函数的作用相匹配。

我不会使用ref或任何带有C代码的ref作为参考,因为C中不存在参考,所以很可能没有达到预期的效果(如果确实如此,它可能会随时中断,因为你是在未指明的世界。)

编辑:关于const。 C中的const和D中的const不是一回事(它在D中是传递的,它不在C中)。同样,程序员决定函数的参数是否可以根据D语义进行const限定。

答案 1 :(得分:1)

C中不存在

in(与const scope相同),因为C. scopeout中不存在ref在C中也不存在。不要将它们与extern(C)函数一起使用。如果你在extern(C)函数的参数中使用它们,编译器可能会给出错误,但如果不这样做,它就不会让我感到惊讶。如果碰巧工作,你只是“幸运”。它可能随时停止工作。如何实现refout是编译器的实现细节。一般来说,你应该只在extern(C)函数中使用修饰符,这些函数实际上存在于C.D的编译器不会做任何魔法来使D个东西在extern(C)函数上运行。它期望extern(C)函数是 C 函数,具有C具有的功能,而不是D.

我所知道的唯一两个例外是purenothrow,因为它们根本不影响调用约定,只是D是否允许您从某些函数调用它们。因此,您可以将C函数标记为pure和/或nothrow。但是如果你用pure标记它(或者你可能会得到令人讨厌的错误),你最好确保该函数实际上是纯粹的 - 与nothrow一样。从技术上讲,也可以使用@safe,@ wrusted和@system,但是C函数确实应该保留为默认值 - @system - 因为它们是C函数。

不,将C函数的参数标记为const不太可能有助于任何优化。如果参数是值类型,那么const从调用者的角度来看是没有意义的。无论如何都会复制参数。它只与参考类型有关。在extern(C)的情况下,它将仅限于指针和带有指针的结构(直接或间接)。 可能在那里进行了一些优化,但我不打赌它 - 特别是对于dmd,它通常不会优化代码以及gdc和ldc。充其量,编译器可以做的是确定在调用之后传入的变量没有改变,这可能启用调用者中的其他优化,但它高度依赖于调用者和编译器。

更重要的是C参数是否实际为const。一般来说,你很好,但在C中,抛弃const并改变变量是合法的,而在D中,it's not。这可能是一个值得关注的问题是immutable数据(字符串文字是一个主要的例子)。如果有任何东西试图实际改变数据,你会冒一个段错误或更糟的风险。一般来说,这不应该是标记为const的C函数参数的问题(虽然它可能偶尔),但它肯定意味着当C不对时将参数标记为const几乎肯定是一个坏主意。如果你这样做,你需要确保变量的值永远不会被C函数实际改变。因为如果你把它标记为const然后C函数会改变它,你就会有bug。

所以,总而言之,我会说,一般来说,你应该只用C修饰符标记extern(C)函数,而不是D特定的函数,你通常不应该将参数标记为{{1除非它们在C中标记为那样。如果您知道C函数实际上是const,您可以将其标记为pure。如果您知道它实际上是pure,则可以使用nothrow进行标记。如果您知道该参数未被C函数突变,那么您可以将其标记为nothrow。但是你应该非常保守,否则你在你的代码中造成令人讨厌的错误。

如果您还没有阅读这些页面:

http://dlang.org/interfaceToC.html
http://dlang.org/htomodule.html