Java 调用由 GCC 编译的 C 库有效,但在使用 G++ 编译时失败

标签 java c gcc g++

我尝试调用这个最小的 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++ 创建库!)一切正常,但如果我用 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)

最佳答案

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"{} block (但上面的例子会导致错误,因为 C 没有函数重载)。

关于Java 调用由 GCC 编译的 C 库有效,但在使用 G++ 编译时失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67899260/

相关文章:

java - xuggler 找不到输入编解码器 ID (avi, msvideo1)

java - java有哪些其他人没有的功能?

c++ - 内联成员函数使用的静态全局变量

c - 生成遵循特定分布的随机 double

c - mmix 上 gcc 的 Printf 问题

c++ - g++ 和 clang++ 在结构/类特化中使用非类型参数的不同行为

java - 使用 Dagger 2 进行 Android 单元测试

java - 在 OSGi 包之间共享对象

C - 通过 FIFO 将在线程中创建的 PIPE FD 发送到父进程

c - 反向 Jenkins 的一次哈希