【问题标题】:Java call to C library compiled by GCC works, but fails when it was compiled with G++对 GCC 编译的 C 库的 Java 调用有效,但在使用 G++ 编译时失败
【发布时间】:2021-08-26 04:03:54
【问题描述】:

我尝试调用这个最小的 C 代码(文件TEST.c): void Java_TEST_run() {}
从这个Java代码(文件Example.java):

public class Example {
    public static void main(String args[]) {
        System.out.println("START");
        TEST test = new TEST();
        test.dll_call();
        System.out.println("ALL DONE!");
    }
}

class TEST {
    public void dll_call() {
        run();
    }

    static {
        try {
            System.out.println("Load DLL = start ");
            System.load("/home/user/Desktop/TEST.dll");
            System.out.println("Load DLL = finish ");
        } catch (UnsatisfiedLinkError e) {
            System.err.println("Native code library failed to load.\n");
            System.exit(1);
        }
    }
    public native void run();
}

我通过以下方式创建一个库:

gcc -c TEST.c                     
g++ -shared -o TEST.dll TEST.o

如果我使用 GCC 编译(甚至使用 G++ 创建 lib!)一切正常,但如果我使用 G++ (g++ -c TEST.c) 编译,我在运行 Java 示例时收到以下错误输出:

START
Load DLL = start 
Load DLL = finish 
Exception in thread "main" java.lang.UnsatisfiedLinkError: 'void TEST.run()'
    at TEST.run(Native Method)
    at TEST.dll_call(Example.java:21)
    at Example.main(Example.java:9)

【问题讨论】:

标签: java c gcc g++


【解决方案1】:

C 和 C++ 是不同的语言,遵循不同的编译规则。如果使用g++ 编译,则代码将被视为 C++ 而不是 C。误解的常见缺陷是 C++ 是 C 的超集。

C++ 做了一种叫做 name mangling 的事情:将函数和变量名编码为唯一的名称,以便链接器可以分隔语言中的常用名称。多亏了它,函数重载等特性才成为可能。

让我们考虑一个例子 (source):

int  f (void) { return 1; }
int  f (int)  { return 0; }
void g (void) { int i = f(), j = f(0); }

编译器可以将上面的内容更改为:

int  __f_v () { return 1; }
int  __f_i (int)  { return 0; } 
void __g_v () { int i = __f_v(), j = __f_i(0); }

尽管g() 的名称是唯一的,但仍然是错误的。名称修改适用于所有 C++ 符号。

如果你想防止名字混淆,你需要使用extern "C"{} 块(但上面的例子会导致错误,因为 C 没有函数重载)。

【讨论】:

  • 谢谢,我同意这似乎与名称修饰有关。我尝试了一些组合,包括。 "__run_v" 但它对我没有用...无论如何,extern"C" 命令成功了。
【解决方案2】:

正如另一个答案中所解释的,失败的原因是 C++ 编译器的名称修改。

要解决这个问题(即让 C++ 与 Java JNI 一起工作),您需要使用 extern "C" language linkage 声明来装饰您的 C++ 函数:

extern "C"
void Java_TEST_run() {}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-13
    相关资源
    最近更新 更多