#java #c #java-native-interface
Вопрос:
Я медленно схожу с ума, так как, несмотря на множество попыток и поисков, я не могу найти жизнеспособного решения этой проблемы.
Я получаю сбой, когда вызываю java / JNI из C с помощью строки.
Любая помощь была бы очень признательна. Я новичок в JNI, поэтому я могу сделать что-то не так, например, должен ли я предварительно выделить буфер памяти и передать его?
Код ниже
Бит Java
public class helloWorld{ public static void main(String[] args){ System.out.println("Hello, World"); } public static int square(int input){ int output = input * input; return output; } public static int power(int input, int exponent){ int output,i; output=1; for(i=0;ilt;exponent;i ){ output *= input; } return output; } public static void hello(String val) { } }
Бит C
#include lt;stdio.hgt; #include lt;stringgt; #include lt;jni.hgt; #include lt;iostreamgt; JNIEXPORT jstring JNICALL Java_com_baeldung_jni_HelloWorldJNI_sayHello (JNIEnv* env) { std::string hello = "Hello from C !!"; std::cout lt;lt; hello lt;lt; std::endl; return env-gt;NewStringUTF(hello.c_str()); } JNIEnv* create_vm(JavaVM **jvm) { JNIEnv* env; JavaVMInitArgs args; JavaVMOption options; args.version = JNI_VERSION_1_6; args.nOptions = 1; options.optionString = (char *)"-Djava.class.path=./"; args.options = amp;options; args.ignoreUnrecognized = 0; int rv = JNI_CreateJavaVM(jvm, (void**)amp;env, amp;args); if (rv lt; 0 || !env) printf("Unable to Launch JVM %dn",rv); else printf("Launched JVM! :)n"); return env; } void invoke_class(JNIEnv* env) { jclass hello_world_class; jmethodID main_method; jmethodID square_method; jmethodID power_method; jint number=20; jint exponent=3; hello_world_class = env-gt;FindClass("helloWorld"); main_method = env-gt;GetStaticMethodID(hello_world_class, "main", "([Ljava/lang/String;)V"); square_method = env-gt;GetStaticMethodID(hello_world_class, "square", "(I)I"); power_method = env-gt;GetStaticMethodID(hello_world_class, "power", "(II)I"); env-gt;CallStaticVoidMethod(hello_world_class, main_method, NULL); printf("%d squared is %dn", number, env-gt;CallStaticIntMethod(hello_world_class, square_method, number)); printf("%d raised to the %d power is %dn", number, exponent, env-gt;CallStaticIntMethod(hello_world_class, power_method, number, exponent)); printf("lalalalalan"); std::string message = "This comes from jni."; const char *result = message.c_str(); jstring argString = env-gt;NewStringUTF(result); jmethodID hello_method = env-gt;GetStaticMethodID(hello_world_class, "hello", "([Ljava/lang/String;)V"); env-gt;CallStaticVoidMethod(hello_world_class, hello_method, argString); } int main(int argc, char **argv) { JavaVM *jvm; JNIEnv *env; env = create_vm(amp;jvm); if(env == NULL) return 1; invoke_class(env); return 0; }
и, наконец, журнал (усек его, так как он был слишком длинным)
# # A fatal error has been detected by the Java Runtime Environment: # # SIGSEGV (0xb) at pc=0x0000000105b76b9c, pid=94283, tid=259 # # JRE version: OpenJDK Runtime Environment (16.0.1 9) (build 16.0.1 9-24) # Java VM: OpenJDK 64-Bit Server VM (16.0.1 9-24, mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, bsd-amd64) # Problematic frame: # V [libjvm.dylib 0x571b9c] jni_CallStaticVoidMethodV 0xcc # # No core dump will be written. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again # # If you would like to submit a bug report, please visit: # https://bugreport.java.com/bugreport/crash.jsp # --------------- S U M M A R Y ------------ Command Line: Host: MacBookPro16,1 x86_64 2300 MHz, 16 cores, 16G, Darwin 20.4.0, macOS 11.3.1 (20E241) Time: Fri Oct 15 13:38:03 2021 BST elapsed time: 0.115419 seconds (0d 0h 0m 0s) --------------- T H R E A D --------------- Current thread (0x00007fc796008a00): JavaThread "main" [_thread_in_vm, id=259, stack(0x00007ffee9e0b000,0x00007ffeea60b000)] Stack: [0x00007ffee9e0b000,0x00007ffeea60b000], sp=0x00007ffeea60a270, free space=8188k Native frames: (J=compiled Java code, A=aot compiled Java code, j=interpreted, Vv=VM code, C=native code) V [libjvm.dylib 0x571b9c] jni_CallStaticVoidMethodV 0xcc C [a.out 0x3701] JNIEnv_::CallStaticVoidMethod(_jclass*, _jmethodID*, ...) 0x171 C [a.out 0x39df] main 0xff C [libdyld.dylib 0x15f3d] start 0x1 siginfo: si_signo: 11 (SIGSEGV), si_code: 1 (SEGV_MAPERR), si_addr: 0x0000000000000000 Register to memory mapping: RAX=0x9d0fb75d63f100d0 is an unknown value RBX=0x00007fc793f05418 points into unknown readable memory: 0x000000070fe19bc8 | c8 9b e1 0f 07 00 00 00 RCX=0x00007fc793f04ad8 points into unknown readable memory: 0x000000070fe1a1a8 | a8 a1 e1 0f 07 00 00 00 RDX=0x0 is NULL RSP=0x00007ffeea60a270 is pointing into the stack for thread: 0x00007fc796008a00 RBP=0x00007ffeea60a310 is pointing into the stack for thread: 0x00007fc796008a00 RSI=0x00007fc793f05418 points into unknown readable memory: 0x000000070fe19bc8 | c8 9b e1 0f 07 00 00 00 RDI=0x00007fc796008d10 points into unknown readable memory: 0x0000000106275e58 | 58 5e 27 06 01 00 00 00 R8 =0x0 is NULL R9 =0x0 is NULL R10=0x00007fff20269e10: __vfprintf.xdigs_lower 0 in /usr/lib/system/libsystem_c.dylib at 0x00007fff201e7000 R11=0xffffffc8ab1fff06 is an unknown value R12=0x00007fc796008a00 is a thread R13=0x00007fc796008d10 points into unknown readable memory: 0x0000000106275e58 | 58 5e 27 06 01 00 00 00 R14=0x0 is NULL R15=0x00007ffeea60a4a0 is pointing into the stack for thread: 0x00007fc796008a00
Комментарии:
1.
main_method =
square_method =
power_method =
— Вам действительно следует проверить, действительны ли они, прежде чем вызывать вызов JNI.2. хорошо, как мне их проверить? но проблема была не в этом, проблема заключалась в сигнатуре метода, переданной Getstaticmethod
3. Если возвращаемое значение равно
nullptr
, это означает, что метод / класс не был найден. Например, верните ошибку в свою программу и посмотрите на возвращаемое значение. Вы должны видеть, чтоhello_method
это nullptr. Это означало бы, что предмет не был найден. При написании кода JNI очень важно проверять наличие любых ошибок и сообщать о них на уровне C . Обратите внимание, что ваша проблема была вызвана ошибкой в наборе текста (или ошибкой при вводе). Это те типы ошибок, которых можно избежать, выполнив проверку на вменяемостьnullptr
.4. Кстати, это распространенная ошибка, когда подпись неверна из-за незнания правильной подписи, или просто толстые пальцы вводят неправильные символы в строке подписи, или какая-то ошибка копирования/вставки.
5. @PaulMcKenzie спасибо вам за весь ваш ценный вклад. 🙂 Очень признателен! Выученный урок проверьте наличие действительного удостоверения личности или проверьте наличие nullptr.
Ответ №1:
Я отвечаю на свой собственный вопрос. Проблема заключалась в сигнатуре метода, переданной JNI с дополнительным [
jmethodID hello_method = env-gt;GetStaticMethodID(hello_world_class, "hello", "([Ljava/lang/String;)V");
jmethodID hello_method = env-gt;GetStaticMethodID(hello_world_class, "hello", "(Ljava/lang/String;)V");
Комментарии:
1. Согласно моему комментарию, вам действительно следует проверить, что все эти функции возвращают действительные идентификаторы.