【问题标题】:A java runtime error with a native JNI static method for C++ implementation用于 C++ 实现的本机 JNI 静态方法的 java 运行时错误
【发布时间】:2020-03-22 23:58:45
【问题描述】:

我有一个带有 two simple implementations 的回购协议,用于使用 C/C++ 的 JNI。
我有 C++ 静态 JNI 方法的 java.lang.UnsatisfiedLinkError 错误。

(base) GlushenkovYuri:java y.glushenkov$ /Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/bin/java -Djava.library.path=. MyJNIExample
Hello World from C!
Exception in thread "main" java.lang.UnsatisfiedLinkError: MyJNIExample.sayHelloCpp()V
        at MyJNIExample.sayHelloCpp(Native Method)
        at MyJNIExample.main(MyJNIExample.java:51)

但对于 C 本机方法,相同的方法也可以很好地工作。 对于没有 static 的 C++ 工作。

您可以通过以下方式重现相同的行为:
1) 用the static native method for C++this one 取消注释行。并用the NON static native method for C++this one 注释行;
2) 只需执行我的README.md 文件中描述的后续步骤即可;

有人可以向我解释为什么原生方法静态/非静态适用于 C,但只有原生非静态方法适用于 C++?

UPD:我的header 文件

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class MyJNIExample */

#ifndef _Included_MyJNIExample
#define _Included_MyJNIExample
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     MyJNIExample
 * Method:    sayHelloC
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_MyJNIExample_sayHelloC
  (JNIEnv *, jclass);

/*
 * Class:     MyJNIExample
 * Method:    sayHelloCpp
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_MyJNIExample_sayHelloCpp
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

【问题讨论】:

标签: java c++ c java-native-interface


【解决方案1】:

javah生成的函数类型根据native方法是否为static而有所不同:

JNIEXPORT void JNICALL Java_MyJNIExample_sayHelloCppstatic
  (JNIEnv *, jclass);

JNIEXPORT void JNICALL Java_MyJNIExample_sayHelloCppnonstatic
  (JNIEnv *, jobject);

此外,生成的标头包含extern "C" 声明,以确保编译器保持名称完整,不会像__Z29Java_MyJNIExample_sayHelloCppP7JNIEnv_P8_jobject 那样对其进行修改。

所以,这里发生的事情是您生成了一个带有static native void sayHelloCpp 的头文件,因此对于带有签名(JNIEnv *, jclass) 的函数有一个extern "C" 声明,但是您提供一个@ 987654331@ 功能。由于签名不匹配,编译器使用其默认修改方案,Java 运行时找不到它。

所以,长话短说:总是在更改 Java 类时重新生成头文件并检查 C++ 函数签名。我无法重现您的问题,因为我编写了一个 Makefile,它总是在重新编译 Java 文件后重新生成头文件。

【讨论】:

  • 当然,当我更改我的 java 文件时,我会重新生成我的标题。我的签名中有 jclass,你可以see。 ``` JNIEXPORT void JNICALL Java_MyJNIExample_sayHelloCpp (JNIEnv *, jclass); ```
  • 但是您的 CPP 文件仍然提到 jobject,所以签名不匹配。
  • 啊,我明白了!谢谢。但后来我想知道为什么它适用于 .c 和 jclass 以及 jobject?为什么带有 jobject 的 .c 作为静态的而 jclass 作为非静态的? C 和 C++ 之间的语义差异是否相同?
  • 名称修饰是 C++ 独有的功能,因为 C 没有函数或方法重载。
  • 我明白了。非常感谢您的解释!
猜你喜欢
  • 2012-01-02
  • 2013-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-21
  • 2020-03-30
  • 2019-08-15
相关资源
最近更新 更多