如何使用 JNI 将 Java ByteBuffer 发送到 C?

Posted

技术标签:

【中文标题】如何使用 JNI 将 Java ByteBuffer 发送到 C?【英文标题】:How to send Java ByteBuffer to C using JNI? 【发布时间】:2017-11-08 08:56:33 【问题描述】:

首先,我想说旧的答案现在不起作用(例如,下面答案中的 GetDirectBufferAddress 函数现在需要一个参数),如下所示:

JNI - native method with ByteBuffer parameter

这里,

how to write and read from bytebuffer passing from java to jni

如果有人帮忙会更好..

因此,我无法使用 JNI 从 Java 将填充了一些元素的 ByteBuffer 正确发送到 C,并且我无法再次将该 ByteBuffer 的元素返回给 C

我的原生函数声明:

public native int myfunc(ByteBuffer pkt);

为其分配

private ByteBuffer pkt = ByteBuffer.allocate(1000);

我这样称呼它:

System.out.println(myfunc(pkt));  // Doesn't works, throws exception
pkt.position(0);
System.out.println(pkt.get()); // works, when I do comment line above .println

我的 C 代码如下:

JNIEXPORT jint JNICALL Java_xxx_myfunc(JNIEnv *, jobject, jobject); // header


JNIEXPORT jint JNICALL Java_xxx_myfunc(JNIEnv *env, jobject obj, jobject pkt) // function

  jbyte *buff = (jbyte *) env->GetDirectBufferAddress(pkt);
  // buff[0] = 0; I've also tried in this way
  return buff[0];
  //return 1; if I return 1, it returns correctly

当我运行 java 程序时,它会抛出异常。如何从 C 中返回填充的 ByteBuffer 值?

编辑

A fatal error has been detected by the Java Runtime Environment:
EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x719c16b8, pid=1096, tid=1900

【问题讨论】:

你能发布堆栈跟踪吗? @Emax 我正在使用不同的电脑进行编码,但将问题编辑为跟踪的开始 好的,但是你在哪里分配 pkt ?您的问题是缺少minimal reproducible example。顺便说一句,所有示例都表明您必须发送env作为第一个参数env->GetDirectBufferAddress(env, buf)编译时是否有警告? @Stargateur 抱歉我忘记了,但我现在编辑了分配行。正如我在问题中指定的那样,我无法为 GetDirectBufferAddress 函数输入两个参数。而且我不确定 buf 是什么。 buf 不是我的 pkt 参数吗?不,没有警告。我认为,如果我的函数出现问题,我无法向 Java 返回 1 值或无法打印 ByteBuffer 的第一个参数 如果您可以通过逐个访问值来生存,请看这里:github.com/mkowsiak/jnicookbook/tree/master/recipeNo040 【参考方案1】:

要使用GetDirectBufferAddress(),您必须保证pktdirect(您可以使用isDirect() 进行检查)。获取此类对象的简单方法是ByteBuffer.allocateDirect()。也可以从 C++ 创建 Direct ByteBuffer。

直接和间接ByteBuffer的区别在Javaoficial doc中有清楚的解释。

更新我看到了你的更新。不,ByteBuffer.allocate(1000) 不会产生 DirectByteBuffer。

正如@Tom Blodget 正确noted,JNI spec 明确表示GetDirectBufferAddress() 可以返回NULL。这适用于两种方式:如果 pkt 是间接 ByteBuffer,则调用本身不应崩溃,但即使您确定 pkt 是 DirectByteBuffer,您也必须检查结果。

【讨论】:

NULL(根据documenation)检查GetDirectBufferAddress() 的结果的“C”操作将比isDirect() 覆盖更多的案例。 @TomBlodget "C" 的事情不会检查NULLisDirect(),是用户函数有责任提供正确的参数(当然函数必须在文档中明确询问这种参数) ;)【参考方案2】:

您不能使用GetDirectBufferAddress(),除非在直接字节缓冲区上。您没有直接字节缓冲区。

【讨论】:

以上是关于如何使用 JNI 将 Java ByteBuffer 发送到 C?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 JNI 将 Java ByteBuffer 发送到 C?

如何将数组从 JNI 返回到 Java?

如何通过JNI将java中的对象的地址赋值给c++指针变量

你应该了解的JNI知识——Java与JNI互相调用

你应该了解的JNI知识——Java与JNI互相调用

如何将字节数组从android java类传递给JNI C NDK?