Java 调用 GCC 编译的 C 库可以工作,但用 G++ 编译时失败

问题描述 投票:0回答:2

我尝试调用这个最小的 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++
2个回答
3
投票

C 和 C++ 是不同的语言,遵循不同的编译规则。如果您使用

g++
进行编译,那么代码将被视为 C++ 而不是 C。C++ 是 C 的超集是误解的常见陷阱。

C++ 执行称为“名称修改”的操作:将函数和变量名称编码为唯一名称,以便链接器可以分隔语言中的通用名称。多亏了它,函数重载等功能才成为可能。 让我们考虑一个例子(

来源

): 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 没有函数重载)。


1
投票

为了解决这个问题(即让 C++ 与 Java JNI 一起工作),您需要使用

extern "C"

语言链接
声明来修饰 C++ 函数: extern "C" void Java_TEST_run() {}

© www.soinside.com 2019 - 2024. All rights reserved.