调用用 void* 调用的 extern C 函数

Calling extern C function called with void*

我有一个 C 库,它在 header.

中采用不透明指针

这是我的 C header

typedef void* dbaxRange_p;
typedef void* dbaxFunction_p;

extern "C" {
    // ... lots of other methods...
    EXPORT dbaxRange_p range_d(const double value);
    EXPORT void add_param(dbaxFunction_p func, dbaxRange_p arg);
    EXPORT dbaxFunction_p dbax_function(const char* name, const int num_params);
    // Call method taking void*
    EXPORT dbaxRange_p call(dbaxFunction_p func);
}

这是我的D界面 CDbax.d:

extern (C):
alias void *dbaxFunction_p;
alias void *dbaxRange_p;

extern (C) {
dbaxRange_p  range_d(double value);
void  add_param(dbaxFunction_p func, dbaxRange_p arg);
dbaxFunction_p  dbax_function(const char *name, int num_params);
dbaxRange_p  call(dbaxFunction_p func);
}

这是我对函数的调用

class Dbax {
     // ...
    dbaxFunction_p func_;
    this(string name) {
       func_ = dbax_function(std.string.toStringz(name),0);
    }
    Dbax add(double val) {
        auto rng = range_d(val);
        add_param(func_,rng);
        return this;
    }
    dbaxRange_p call() {
        return call(cast(dbaxFunction_p) this.func_);
    }
}

main.d

import CDbax;
void test()
{
    auto res = new CDbax.Dbax("GetVersionNumber").add(0.24).call();
}

但是我得到这个错误:-

CDbax.d(113): Error: function CDbax.Dbax.call () is not callable using argument types (void*)

更新 答案是存在命名空间冲突。它获取了我的 C FFI 调用而不是 Dbax class call() 函数。我会问一个跟进的问题,为什么

这只是它尝试调用方法 call 而不是全局函数的一个例子。 (顺便说一句,你确定 C 函数被称为 call 而这不是宏吗?C 函数很少有这样一个裸名。)

无论如何,当您在 class 中时,它总是首先查找 class 的成员,并且 D 不会 跨单元超载,除非您通过 alias innerName = full.outer.name; 明确要求它这样做的原因在这里的解释:http://dlang.org/hijack.html 基本上是这样,稍后添加全局函数不会通过引入新的、令人困惑的重载来破坏 class。 class' 作者应该能够只关注 class' 源代码,而不必担心另一个程序员在一个很远很远的模块中编写的新全局变量会使她的代码更加混乱。

在您的情况下解决此问题的最简单方法是使用全名,或者至少在您的调用中使用全局范围运算符:

    return call(cast(dbaxFunction_p) this.func_); // before

    return .call(cast(dbaxFunction_p) this.func_); // after

前导点表示 "look it up in the top-level namespace"。 (顺便说一句,类似地,当您希望它只查看 this 时,您可以显式使用 this.call。)

当出现这些情况时,如果您希望更明确,也可以在模块名称前加上模块名称以消除歧义:

  foo.bar.call(); // looks in foo.bar