JNI“env-> GetStaticMethodID()”崩溃的程序

我正在尝试从C ++调用Java函数。 到目前为止这是我的代码:

#include  typedef struct JavaVMCreationResult { JavaVM* jvm; JNIEnv* env; } JVMCreationResult; JVMCreationResult* CreateJavaVM() { JavaVM* jvm; JNIEnv* env; JavaVMInitArgs args; JavaVMOption opts[1]; opts[0].optionString = "-Djava.class.path=C:\\MyJavaClasses"; args.version = JNI_VERSION_1_6; args.nOptions = 1; args.options = opts; args.ignoreUnrecognized = JNI_TRUE; JNI_GetDefaultJavaVMInitArgs(&args); JNI_CreateJavaVM(&jvm, (void **) &env, &args); JavaVMCreationResult* cres; cres->jvm = jvm; cres->env = env; return cres; } int main() { JVMCreationResult* cres = CreateJavaVM(); JavaVM* jvm = cres->jvm; JNIEnv* env = cres->env; jclass cls = env->FindClass("Main"); jmethodID mid = env->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V"); // the evil line } 

我在Windows 7上使用Code :: Blocks和MinGW GCC。
main()函数的最后一行使程序崩溃,但编译器不会抱怨任何事情。 (注释掉jmethodID mid = env->GetSta...程序“没有崩溃”)
我使用javap -s Main来获取正确的方法签名,该类也是一个有效的Java类。

你能告诉我程序崩溃的原因吗? 这个例子只是在互联网上随处可见,但它对我不起作用。 🙁

这是Java类:

 public class Main { public static void main(String[] args) { System.out.println("This is from Java !"); } } 

我不会想到这一点,对于我来说,当结构未初始化时,程序没有崩溃,这似乎是不合逻辑的。 但这确实是个问题。
这是完整且有效的代码!

 #include  #ifndef null #define null NULL #endif typedef struct JavaVMCreationResult { JavaVM* jvm; JNIEnv* env; } JVMCreationResult; JVMCreationResult* CreateJavaVM() { JavaVM* jvm; JNIEnv* env; JavaVMInitArgs args; JavaVMOption opts[1]; opts[0].optionString = "-Djava.class.path=C:\\Users\\Claudia\\Desktop"; args.version = JNI_VERSION_1_6; args.nOptions = 1; args.options = opts; args.ignoreUnrecognized = JNI_TRUE; JNI_GetDefaultJavaVMInitArgs(&args); JNI_CreateJavaVM(&jvm, (void **) &env, &args); JVMCreationResult* cres = new JVMCreationResult(); cres->jvm = jvm; cres->env = env; return cres; } int main() { JVMCreationResult* cres = CreateJavaVM(); JavaVM* jvm = cres->jvm; JNIEnv* env = cres->env; jclass cls = env->FindClass("Main"); if (cls) { printf("Yes !\n"); } else { printf("No !\n"); } jmethodID mid = env->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V"); env->CallStaticVoidMethod(cls, mid); printf("At end of Program."); } 

您的变量“cres”是CreateJavaVM调用中永远不会初始化的一个点,因此您可能在该点取消引用null或其他无效指针。

一种解决方案是在main中定义cres(不是指向cres的指针),并将指向的指针传递给CreateJavaVM作为参数,然后使用CreateJavaVM中的参数返回结果。

在JNI_CreateJavaVM调用之后检查jvm和env是否获得非空值是个好主意,并且在分别调用FindClass和GetStaticMethodID之后cls和mid同样是非null的。

cls可能无效。 如果’cres’为null,我认为你的程序会先崩溃。

 int main() { JVMCreationResult* cres = CreateJavaVM(); if(!cres) return -1; JavaVM* jvm = cres->jvm; JNIEnv* env = cres->env; jclass cls = env->FindClass("Main"); if(env->ExceptionCheck()) { // ClassNotFoundException ? env->ExceptionDescribe(); env->ExceptionClear(); } if(!cls) return -2; // this I think is your problem jmethodID mid = env->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V"); // the evil line } 

您确定您的类路径已正确指定吗? 希望FindClass(“Main”)将找到一个默认的包类。 无论如何,如果您的C / C ++ main()现在告诉我们返回值。

有可能是“JavaVM * jvm = cres-> jvm;” 因为“jvm”从未被引用而且语句“cres-> jvm”没有副作用。 一些评论者表示它应该崩溃,嗯可能,如果代码生成然后执行。 但是一个体面的编译器可能会认为这是一个无操作。

但是声明“JNIEnv * env = cres-> env;” 无法优化,因为稍后使用变量“env”。 所以我们只能声称如果cres == 0那么它会在执行此点或之前崩溃。 由于“env”用于FindClass()调用,因此我们确定env!= 0因此cres!= 0。

我猜你有类路径设置问题,FindClass()没有在运行时找到你的类,导致“cls == 0”为真。 这是我的答案。

编辑:我看到其他人对“cres”的主张是什么,但这并没有改变我原来的诊断,但你仍然有一个关于’cres’的错误,将行更改为:

 JavaVMCreationResult* cres = new JavaVMCreationResult; 

我认为你很幸运cres指向某处(可能在堆栈上),然后将值复制到本地main()堆栈并使用这些值。 但这并没有使这项技术正确,因为’cres’指向的初始内存是随机的,所以你很幸运没有发生崩溃,但你确实在你应该没有的内存上涂鸦。 通过使用“cres = new JavaVMCreationResult;” 这会导致指针被设置为已知的有效内存块。

如果您希望编译器协助解决此问题(即它应该显示警告),请在编译期间使用MinGW“-Wall”和“-O2”选项。 它应警告未初始化使用变量’cres’。