我正在尝试从C ++调用Java函数。 到目前为止,这是我的代码:
#include <jni.h>
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 <jni.h>
#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.");
}
答案 0 :(得分:5)
您的变量“cres”是CreateJavaVM调用中从未初始化的一个点,因此您可能在该点取消引用null或其他无效指针。
一种解决方案是在main中定义cres(不是指向cres的指针),并将指向的指针传递给CreateJavaVM作为参数,然后使用CreateJavaVM中的参数返回结果。
同样最好在JNI_CreateJavaVM调用之后检查jvm和env是否获得非空值,并且在分别调用FindClass和GetStaticMethodID之后cls和mid同样是非null
答案 1 :(得分:2)
cls可能无效。如果'cres'为空,我认为你的程序会先崩溃。
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-&gt; jvm;”因为“jvm”从未被引用而且语句“cres-&gt; jvm”没有副作用。一些评论者表示它应该崩溃,嗯,是的,如果代码生成然后执行。但是一个体面的编译器可能会认为这是一个无操作。
然而声明“JNIEnv * env = cres-&gt; 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'。