【问题标题】:How method Identified in JNI?JNI中如何识别方法?
【发布时间】:2016-09-14 19:12:00
【问题描述】:

在开发过程中,由于错误,我错过了在函数中添加参数。但是本机 jni 调用中的相同函数具有参数。但它仍然从java调用精确的方法。

Java 类 Demo.java

  package jniexamples.rmi;

class Demo {
    private native void jBoolean();
    public static void main(String[] args) {
        new Demo().jBoolean();
    }
    static {
        System.load("jnidemo.so");
    }
}

Demo.c

 #include <jni.h>
#include <stdio.h>
JNIEXPORT void JNICALL
Java_jniexamples_rmi_Demo_jBoolean(JNIEnv *env, jobject ob,jint dtype)
{
    printf("first demo %d" , dtype);
    return;
}

结果:第一个演示 -1579007728

即使方法签名不同,我也很困惑,它是如何调用 jni 方法的?

【问题讨论】:

  • 看起来你只是得到了缺少参数的未定义值
  • 该方法由其名称标识。您需要确保签名匹配。
  • IIRR,你应该包含javah生成的.h头文件,以确保你有正确的函数原型
  • 如果我有两个方法并且名称相同但参数不同,那么没有标题就会有问题。
  • @Nilesh 没有其他正确的方法可以做到这一点。 JVM 和 javah 共享 Java 本地方法签名如何映射到 C 的确切知识。javah 将生成正确的头文件,并由您确保 .c 文件与它一致。跨度>

标签: java c java-native-interface


【解决方案1】:

C 函数仅在链接期间和运行时由名称标识,因此 Java 将调用该函数但不提供任何参数。

如果在调用 C 函数时提供的参数太少,则会调用未定义的行为,这意味着任何事情都可能发生。 (在您的情况下,您得到了一个看似随机的值。)

javah 生成的头文件将包含具有正确签名的函数声明。如果包含生成的标头,编译器可以将标头中的签名与.c 文件中的签名进行比较,如果它们不同,则会在编译时发出错误。

【讨论】:

  • 谢谢,我是 Jni 和 C 的新手。但是在这种情况下,头文件会有什么帮助呢?
  • @Nilesh 生成的头文件将包含具有正确签名的函数声明。如果包含生成的标头,编译器可以将标头中的签名与 .c 文件中的签名进行比较,如果它们不同,则会在编译时发出错误。
【解决方案2】:

非常简短的场景如下所示。当您从 java 调用 jBoolean() 时,JVM 注意到此方法是本机的,并尝试找到它的实现。在您的情况下,JVM 通过使用类和包名称装饰 jBoolean 来构造本机函数的名称。结果是字符串Java_jniexamples_rmi_Demo_jBoolean。然后它会尝试在进程的地址空间中使用dlsym() 查找具有此名称的函数。因此,在尝试调用它之前使用此函数加载本机模块至关重要。然后,如果没问题 - dlsym() 返回指向函数的指针,但请注意,该指针没有关于实际函数签名和 JVM infers 仅使用在 java 中声明的原生签名的信息。然后JVM根据推断的签名调用你的本机函数。

结果 - 推断签名和实际签名之间的差异会导致未定义的行为,这可能会导致非常奇怪的事情,而不仅仅是随机参数值。因此,这是一个很好的做法 - 将 javah-generated 标头包含到您的本机实现中。如果您的实现之一具有与标头中声明的签名不同的签名,则此类标头会因错误而中断编译。

【讨论】:

  • 感谢 Serhio,它让我了解了 JVM 如何将 java 函数映射到本机函数,以及头文件的使用
猜你喜欢
  • 2023-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多