JNA:如何将字符串作为 void* 从 Java 传递给 C

JNA: How to pass a string as void* from Java to C

我已经成功收到一个来自 C 函数的 void* 到 Java 并根据上下文将其转换为适当的类型,但现在我必须做整个事情反过来了,我无法让它工作。

具体来说,我试图调用的函数需要一个 void*,在这种情况下,它后面隐藏了一个 char*,当然在它后面隐藏了一个 char[]。 C 函数不操作数据,它只是读取数据。

所以我尝试从字符串创建一个 Byte[],然后将指针传递给它的第一个元素,如下所示:

    //transform the string into a byte array
    byte[] byte_value = new_value.getBytes();
    //create a pointer to the first byte
    ByteByReference valueptr = new ByteByReference(byte_value[0]);
    //pass the pointer to the function that sets the value
    int result = lib.gp_widget_set_value(widget, valueptr.getPointer()); 

令我惊讶的是,没有任何崩溃。令我沮丧的是,该函数似乎根本无法获取数据。有人能看出我做错了什么吗?

函数gp_widget_set_value是JNAerator基于libgphoto2生成的。生成的函数头包括生成的注释如下所示:

/**
 * Original signature : <code>int gp_widget_set_value(CameraWidget*, const void*)</code><br>
 * <i>native declaration : /usr/include/gphoto2/gphoto2-widget.h:840</i>
 */
int gp_widget_set_value(Gphoto2Library.CameraWidget widget, Pointer value);

来自 Gphoto API 文档的实际 C 函数的文档:

int gp_widget_set_value ( CameraWidget * widget, const void * value )

Sets the value of the widget.

Parameters widget a CameraWidget value

Returns a gphoto2 error code.

Please pass (char*) for GP_WIDGET_MENU, GP_WIDGET_TEXT, GP_WIDGET_RADIO, (float) for GP_WIDGET_RANGE, (int) for GP_WIDGET_DATE, GP_WIDGET_TOGGLE, and (CameraWidgetCallback) for GP_WIDGET_BUTTON.

如果您想知道,最后一行是指小部件类型,是的,我非常确定这是正确的。

您可以使用以下方法获取正确编码的字节:

byte[] bytes = new_value.getBytes( StandardCharsets.UTF_8 ); //or .US_ASCII

但您最有可能需要做的是使用 JNA's byte[] Native.toByteArray(String s)

如果由于某种原因不起作用,那么应该这样做:

Pointer m = new Memory( new_value.length() + 1 ); //assumes ASCII
m.setString( 0, new_value );
int result = lib.gp_widget_set_value( widget, m );

您不需要任何复杂的东西。 JNA 处理最常见的 C 习语。 JNAerator 从字面上为您提供函数声明中的内容;它无法弄清楚 C 字符串、字符缓冲区、字符数组或指向单个字符的指针之间的语义差异。

int gp_widget_set_value(Gphoto2Library.CameraWidget widget, String value);

请注意,在这种情况下传递给本机函数的内存是临时的,将在函数 returns 时被处理掉。如果您需要保留内存(这不是一个好主意),您需要使用 Memory 并维护对它的引用。