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
并维护对它的引用。
我已经成功收到一个来自 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
并维护对它的引用。