JNI "env->GetStaticMethodID()" abgestürztes Programm
Bin ich versucht, rufen Sie eine Java-Funktion von C++.
Das ist mein code bisher:
#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
}
Ich bin mit Code::Blocks mit MinGW-GCC auf Windows 7.
Die Letzte Zeile in der main () - Funktion, die das Programm stürzt ab, aber der compiler beschwert sich nicht über alles. (Auskommentieren der jmethodID mid = env->GetSta...
Linie macht das Programm nicht "abstürzt")
Ich habe verwendet javap -s Main
zu erhalten, die richtige Methode, Signatur, auch die Klasse ist eine gültige Java-Klasse.
Können Sie mir sagen, warum das Programm abstürzt ? In diesem Beispiel wird nur gezeigt, überall im Internet, aber es funktioniert nicht für mich. 🙁
Dies ist die Java-Klasse:
public class Main {
public static void main(String[] args) {
System.out.println("This is from Java !");
}
}
LÖSUNG
Ich würde nicht gedacht haben, es scheint eine Unlogik zu mir, dass das Programm nicht abstürzt, früher, wenn die struct nicht initialisiert. Aber das war wirklich das Problem.
Dies ist die vollständige und funktionierenden code !
#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.");
}
- Deine variable "cres" ist ein Punkt in der CreateJavaVM nennen, die noch nie initialisiert, also bist du wahrscheinlich dereferenzieren eines null-oder anderweitig ungültigen Zeiger auf diesen Punkt.
- Würde das nicht bedeuten sollte das Programm Abstürzen, an der Stelle
JavaVM* jvm = cres->jvm;
? Und warum ist es nicht initialisiert ? (Ich bin kein C++ Experte, begann vor einigen Wochen.) Dank - Wie Sie wissen, kracht es in der letzten Zeile von main()?
- Yep,
cres
ist nicht verweist auf Speicher zugewiesen. Wenn überhaupt sollte es crash aufcres->jvm = jvm
eigentlich. - Ich weiß es, weil es funktioniert, wenn ich die folgende Zeile auskommentiert werden. Ach so, ich sollte das Schlüsselwort new, verwenden ? (Wie gesagt, ziemlich neu in C++ und Zeiger) Seltsam, wenn dies wirklich das Problem, der compiler gar nicht beklagen, dass "null-pointer".
- Compiler nicht erkennen kann null-Zeiger, da Sie generiert eine run-time.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Variable "cres" ist ein Punkt in der CreateJavaVM nennen, die noch nie initialisiert, also bist du wahrscheinlich dereferenzieren eines null-oder anderweitig ungültigen Zeiger auf diesen Punkt.
Einer Lösung ist, um zu definieren, cres (und nicht einen Zeiger auf cres) in Haupt -, und übergeben Sie einen Zeiger auf , dass zu CreateJavaVM als parameter, und verwenden Sie dann die parameter in CreateJavaVM das Ergebnis zurückgeben.
Außerdem ist es eine gute Idee zu überprüfen, dass die jvm und env bekommen nicht-null-Werte nach der JNI_CreateJavaVM call, und, dass cls und Mitte sind ebenfalls ungleich null, nachdem die Aufrufe an FindClass und GetStaticMethodID, bzw.
jclass cls = env->FindClass("Main");
?! Initialisieren der struct funktioniert ! Vielen Dank !cls ist wahrscheinlich ungültig. Ich nehme an, Ihr Programm würde haben stürzte früher, wenn 'cres' war null.
Sind Sie sicher, dass der classpath angegeben wurde, richtig ? Hoffentlich FindClass("Main") wird ein Standard-Paket. Klasse. Jedenfalls sagen uns die Rückkehr Wert, wenn Ihr C/C++ main () - jetzt.
Ist es möglich, für die "JavaVM* jvm = cres->jvm;" optimiert werden entfernt, da "jvm" ist nie auf die verwiesen wird und die Aussage "cres->jvm" und hat keine Nebenwirkungen. Einige Kommentatoren Staat sollte es zum Absturz über diese, hmm ja vielleicht, wenn der code wurde generiert und anschließend ausgeführt. Aber eine anständige compiler kann sehen es ist kein Vorgang.
Jedoch die Aussage "JNIEnv* env = cres->env;" kann nicht optimiert werden, Weg, da die variable "env" wird später verwendet. Wir können also nur behaupten, dass, wenn cres==0, dann ist es Abstürzen würde, auf oder vor diesem Zeitpunkt in der Ausführung. Da "env" ist für FindClass() nennen, dann wissen wir sicher, dass env!=0 und somit cres!=0.
Ich würde vermuten, Sie haben eine Klasse Pfad-setup-Problem, FindClass() ist nicht zu finden, Ihre Klasse zur Laufzeit, die verursacht wird "cls==0", um wahr zu sein. Das ist meine Antwort hier.
EDITIERT: ich sehe, was die anderen zu fordern, über 'cres' allerdings, dass ändert nichts an meiner ursprünglichen Diagnose, aber Sie haben noch einen Fehler in Bezug auf 'cres', ändern Sie die Zeile:
Ich denke, Sie sind glücklich, dass cres verweist irgendwo (wahrscheinlich auf dem stack), dann kopiert die Werte in die lokale main() stack und die Werte benutzt. Aber das heißt nicht, dass die Technik korrekt wie der erste Speicher, die 'cres' hinweist, ist zufällig, so haben Sie Glück, dass kein Absturz mehr aufgetreten, aber du hast Freihand auf Speicher, den Sie nicht haben sollte. Durch die Verwendung des "cres = new JavaVMCreationResult;" dies bewirkt, dass der Zeiger auf einen gültigen Speicherblock.
Wenn Sie möchten, compiler-Unterstützung mit diesem problem (d.h. es sollte zeigen, bis eine Warnung) versuchen mit MinGW "-Wall" und "-O2" Optionen beim kompilieren. Es sollte warnen über nicht initialisierte Verwendung der variable 'cres'.