如何在 JNA 中映射结构内的结构数组而不在 C++ 声明中设置数组大小
How to map in JNA an array of structure inside a structure without setting the array size on the C++ declaration
我试图在 JNA 中映射一个包含结构数组的结构。
嵌入式结构的大小不是在结构的 C++ 声明中预先定义的,而是在 java 代码中定义的。
我的问题是我在线程“main”中得到异常java.lang.Error:无效内存访问
C++header文件如下:
typedef struct s_Param
{
char* key;
uint32_t key_value;
} Param;
typedef struct s_ParamList {
Param* init_param;
int param_list_size; // number of param items in the param List
} ParamList;
C++代码如下:
int Init(
ParamList* i_initParamList,
logfunction i__callback,
const allocator* i__allocator,
void** o__content) {
...
if (i_initParamList != NULL){
printf("DLL PRINT init ---- i_initParamList = %p\n", i_initParamList);
printf("DLL PRINT init ---- i_initParamList->param_list_size = %i\n", i_initParamList->param_list_size);
if (i_initParamList->init_param == NULL){
printf("DLL PRINT init ---- i_initParamList->init_param must not be NULL\n");
returnedCode = 1;
}else{
for (int i = 0; i<i_initParamList->param_list_size;i++){
printf("DLL PRINT init ---- i_initParamList->init_param[i]->key = %s\n",i_initParamList->init_param[i].key);
printf("DLL PRINT init ---- i_initParamList->init_param[i]->key_value = %i\n",i_initParamList->init_param[i].key_value);
}
...
}
javaJNA代码如下:
public interface MyLibrary extends Library {
@FieldOrder({ "key", "key_value" })
public static class Param extends Structure {
public static class ByReference extends Param implements Structure.ByReference {
}
public String key;
public int key_value;
public Param(){ // NOT sure that this adding constructor makes sense
super();
setAlignType(ALIGN_NONE);
}
}
@FieldOrder({ "init_param", "param_list_size" })
public static class ParamList extends Structure {
public static class ByReference extends ParamList implements Structure.ByReference {
}
public Param[] init_param;
public int param_list_size;
ParamList(){ // NOT sure that this adding constructor makes sense
super();
setAlignType(ALIGN_NONE);
}
}
public int Init(ParamList i_initParamList, logfunction i__callback, allocator i__allocator,
PointerByReference o__content);
...
}
调用JNA库的Sample.java代码如下:
请注意,我没有添加 Init 函数的其他参数的管理方式,因为我对它们没有任何问题。
int paramListSize = 4;
MyLibrary.Param[] params = new MyLibrary.Param[paramListSize];
for (int i = 0; i < paramListSize; i++) {
params[i] = new MyLibrary.Param();
}
params[0].key = "first";
params[0].key_value = 1;
params[1].key = "second";
params[1].key_value = 5;
params[2].key = "third";
params[2].key_value = 7;
params[3].key = "forth";
params[3].key_value = 9;
MyLibrary.ParamList paramList = new MyLibrary.ParamList.ByReference();
paramList.init_param = params;
paramList.param_list_size = paramListSize;
logger.debug("params = "+ params);
logger.debug("paramList = "+ paramList);
logger.debug("paramList.param_list_size = "+paramList.param_list_size);
int errInit = IFunctions.Init(paramList, logCallback, i__allocator, o__content);
来自C++和Java代码的跟踪结果如下:
10:41:28,303 DEBUG Sample:193 - params = [MyLibrary$Param;@1e67a849
10:41:28,312 DEBUG Sample:194 - paramList = MyLibrary$ParamList$ByReference(auto-allocated@0x1f3d49fe5b0 (52 bytes)) {
MyLibrary$Param init_param[4]@0x0=[MyLibrary$Param;@1e67a849
int param_list_size@0x30=0x0004
}
10:41:28,316 DEBUG Sample:195 - paramList.param_list_size = 4
Exception in thread "main" java.lang.Error: Invalid memory access
at com.sun.jna.Native.invokeInt(Native Method)
at com.sun.jna.Function.invoke(Function.java:426)
at com.sun.jna.Function.invoke(Function.java:361)
at com.sun.jna.MyLibrary$Handler.invoke(MyLibrary.java:265)
at com.sun.proxy.$Proxy3.init(Unknown Source)
at Sample.main(Sample.java:216)
DLL PRINT init ---- i_initParamList = 000001F3D49FE5B0
DLL PRINT _init ---- init_param address = 0000021B4ADAF3D0
DLL PRINT init ---- i_initParamList->param_list_size = 1
DLL PRINT init ---- i_initParamList->init_param[i]->key =
如果我在 C++ header 中声明我的结构如下:
typedef struct s_ParamList {
Param init_param[4];
int param_list_size; // number of param items in the param List
} ParamList;
但我不想在 C++ 代码中定义 init_param 数组大小,因为它必须在 java 代码端定义。
关于在 java代码中添加以下代码:
ParamList(){ // NOT sure that this adding constructor makes sense
super();
setAlignType(ALIGN_NONE);
}
我不确定我是否必须在两个结构中添加它,即在 ParamList 和 Param 结构中。
但是无论如何,如果我删除这两个构造函数,我会遇到完全相同的问题。
我看到了另一种管理我的要求的方法(查看 5.8.0 JNA 版本的 https://javadoc.io/doc/net.java.dev.jna/jna/latest/index.html 结构一章中的 toArray(size) 方法。
事实上,我也遵循了 link How to fill an array of structures in JNA? 但我得到了无效的内存访问。如果我不能在结构中包含我的结构数组,我将针对第二种实现创建一个单独的问题。
而且我必须将 Param 数组和数组的大小拆分为 Init 函数的 2 个单独参数,而不是将它们设置为唯一的结构。
由于我的 Init 函数中已经有很多参数,所以我宁愿只有一个结构参数。我想在 JNA 中应该是可能的。
有人知道吗?
感谢您的帮助。
可以考虑下面的数据结构吗?
typedef struct s_ParamList {
int param_list_size; // number of param items in the param List
Param init_param[0];
} ParamList;
如果是,请准确分配内存和数组使用,因为这种方法很危险,很容易导致数据溢出
问题出在你对这个结构的映射
typedef struct s_ParamList {
Param* init_param;
int param_list_size; // number of param items in the param List
} ParamList;
*
表示这是一个指向您需要定义的别处内存的指针。
结构在结构内部默认被视为 ByValue,在函数参数中默认被视为 ByRefrence。所以这里你需要显式定义结构的 ByReference 版本(或者使用类型安全性较低的普通指针。)
所以你会把它作为结构的主要部分。
@FieldOrder({ "init_param", "param_list_size" })
public static class ParamList extends Structure {
public Param.ByReference init_param;
public int param_list_size;
}
接下来,您已表示要定义此数组并在 Java 中自行分配其内存。这里要记住的重要一点是 C 将数组视为连续内存,因此您实际上只有两个选择:使用 Memory
自己分配一个大块并手动设置偏移量的值;或使用专为这种情况设计的 Structure.toArray()
:您从一个实例化结构开始,然后告诉 toArray()
方法您需要它的副本数。
因此您的示例代码如下所示:
int paramListSize = 4;
// Note the syntax for allocating a contiguous array
MyLibrary.Param.ByReference[] params =
(MyLibrary.Param.ByReference[]) new MyLibrary.Param.ByReference().toArray(paramListSize);
// set the values as you've alread done
params[0].key = "first";
params[0].key_value = 1;
// and so on...
// Now instantiate your structure and set its members
MyLibrary.ParamList paramList = new MyLibrary.ParamList();
// The first array member is the pointer to the start of the array
paramList.init_param = params[0];
paramList.param_list_size = paramListSize;
在这里,您将它传递给本机函数。默认是ByReference。
你可以找另一个通用的例子here
我试图在 JNA 中映射一个包含结构数组的结构。 嵌入式结构的大小不是在结构的 C++ 声明中预先定义的,而是在 java 代码中定义的。 我的问题是我在线程“main”中得到异常java.lang.Error:无效内存访问
C++header文件如下:
typedef struct s_Param
{
char* key;
uint32_t key_value;
} Param;
typedef struct s_ParamList {
Param* init_param;
int param_list_size; // number of param items in the param List
} ParamList;
C++代码如下:
int Init(
ParamList* i_initParamList,
logfunction i__callback,
const allocator* i__allocator,
void** o__content) {
...
if (i_initParamList != NULL){
printf("DLL PRINT init ---- i_initParamList = %p\n", i_initParamList);
printf("DLL PRINT init ---- i_initParamList->param_list_size = %i\n", i_initParamList->param_list_size);
if (i_initParamList->init_param == NULL){
printf("DLL PRINT init ---- i_initParamList->init_param must not be NULL\n");
returnedCode = 1;
}else{
for (int i = 0; i<i_initParamList->param_list_size;i++){
printf("DLL PRINT init ---- i_initParamList->init_param[i]->key = %s\n",i_initParamList->init_param[i].key);
printf("DLL PRINT init ---- i_initParamList->init_param[i]->key_value = %i\n",i_initParamList->init_param[i].key_value);
}
...
}
javaJNA代码如下:
public interface MyLibrary extends Library {
@FieldOrder({ "key", "key_value" })
public static class Param extends Structure {
public static class ByReference extends Param implements Structure.ByReference {
}
public String key;
public int key_value;
public Param(){ // NOT sure that this adding constructor makes sense
super();
setAlignType(ALIGN_NONE);
}
}
@FieldOrder({ "init_param", "param_list_size" })
public static class ParamList extends Structure {
public static class ByReference extends ParamList implements Structure.ByReference {
}
public Param[] init_param;
public int param_list_size;
ParamList(){ // NOT sure that this adding constructor makes sense
super();
setAlignType(ALIGN_NONE);
}
}
public int Init(ParamList i_initParamList, logfunction i__callback, allocator i__allocator,
PointerByReference o__content);
...
}
调用JNA库的Sample.java代码如下: 请注意,我没有添加 Init 函数的其他参数的管理方式,因为我对它们没有任何问题。
int paramListSize = 4;
MyLibrary.Param[] params = new MyLibrary.Param[paramListSize];
for (int i = 0; i < paramListSize; i++) {
params[i] = new MyLibrary.Param();
}
params[0].key = "first";
params[0].key_value = 1;
params[1].key = "second";
params[1].key_value = 5;
params[2].key = "third";
params[2].key_value = 7;
params[3].key = "forth";
params[3].key_value = 9;
MyLibrary.ParamList paramList = new MyLibrary.ParamList.ByReference();
paramList.init_param = params;
paramList.param_list_size = paramListSize;
logger.debug("params = "+ params);
logger.debug("paramList = "+ paramList);
logger.debug("paramList.param_list_size = "+paramList.param_list_size);
int errInit = IFunctions.Init(paramList, logCallback, i__allocator, o__content);
来自C++和Java代码的跟踪结果如下:
10:41:28,303 DEBUG Sample:193 - params = [MyLibrary$Param;@1e67a849
10:41:28,312 DEBUG Sample:194 - paramList = MyLibrary$ParamList$ByReference(auto-allocated@0x1f3d49fe5b0 (52 bytes)) {
MyLibrary$Param init_param[4]@0x0=[MyLibrary$Param;@1e67a849
int param_list_size@0x30=0x0004
}
10:41:28,316 DEBUG Sample:195 - paramList.param_list_size = 4
Exception in thread "main" java.lang.Error: Invalid memory access
at com.sun.jna.Native.invokeInt(Native Method)
at com.sun.jna.Function.invoke(Function.java:426)
at com.sun.jna.Function.invoke(Function.java:361)
at com.sun.jna.MyLibrary$Handler.invoke(MyLibrary.java:265)
at com.sun.proxy.$Proxy3.init(Unknown Source)
at Sample.main(Sample.java:216)
DLL PRINT init ---- i_initParamList = 000001F3D49FE5B0
DLL PRINT _init ---- init_param address = 0000021B4ADAF3D0
DLL PRINT init ---- i_initParamList->param_list_size = 1
DLL PRINT init ---- i_initParamList->init_param[i]->key =
如果我在 C++ header 中声明我的结构如下:
typedef struct s_ParamList {
Param init_param[4];
int param_list_size; // number of param items in the param List
} ParamList;
但我不想在 C++ 代码中定义 init_param 数组大小,因为它必须在 java 代码端定义。
关于在 java代码中添加以下代码:
ParamList(){ // NOT sure that this adding constructor makes sense
super();
setAlignType(ALIGN_NONE);
}
我不确定我是否必须在两个结构中添加它,即在 ParamList 和 Param 结构中。 但是无论如何,如果我删除这两个构造函数,我会遇到完全相同的问题。
我看到了另一种管理我的要求的方法(查看 5.8.0 JNA 版本的 https://javadoc.io/doc/net.java.dev.jna/jna/latest/index.html 结构一章中的 toArray(size) 方法。 事实上,我也遵循了 link How to fill an array of structures in JNA? 但我得到了无效的内存访问。如果我不能在结构中包含我的结构数组,我将针对第二种实现创建一个单独的问题。 而且我必须将 Param 数组和数组的大小拆分为 Init 函数的 2 个单独参数,而不是将它们设置为唯一的结构。 由于我的 Init 函数中已经有很多参数,所以我宁愿只有一个结构参数。我想在 JNA 中应该是可能的。
有人知道吗?
感谢您的帮助。
可以考虑下面的数据结构吗?
typedef struct s_ParamList {
int param_list_size; // number of param items in the param List
Param init_param[0];
} ParamList;
如果是,请准确分配内存和数组使用,因为这种方法很危险,很容易导致数据溢出
问题出在你对这个结构的映射
typedef struct s_ParamList {
Param* init_param;
int param_list_size; // number of param items in the param List
} ParamList;
*
表示这是一个指向您需要定义的别处内存的指针。
结构在结构内部默认被视为 ByValue,在函数参数中默认被视为 ByRefrence。所以这里你需要显式定义结构的 ByReference 版本(或者使用类型安全性较低的普通指针。)
所以你会把它作为结构的主要部分。
@FieldOrder({ "init_param", "param_list_size" })
public static class ParamList extends Structure {
public Param.ByReference init_param;
public int param_list_size;
}
接下来,您已表示要定义此数组并在 Java 中自行分配其内存。这里要记住的重要一点是 C 将数组视为连续内存,因此您实际上只有两个选择:使用 Memory
自己分配一个大块并手动设置偏移量的值;或使用专为这种情况设计的 Structure.toArray()
:您从一个实例化结构开始,然后告诉 toArray()
方法您需要它的副本数。
因此您的示例代码如下所示:
int paramListSize = 4;
// Note the syntax for allocating a contiguous array
MyLibrary.Param.ByReference[] params =
(MyLibrary.Param.ByReference[]) new MyLibrary.Param.ByReference().toArray(paramListSize);
// set the values as you've alread done
params[0].key = "first";
params[0].key_value = 1;
// and so on...
// Now instantiate your structure and set its members
MyLibrary.ParamList paramList = new MyLibrary.ParamList();
// The first array member is the pointer to the start of the array
paramList.init_param = params[0];
paramList.param_list_size = paramListSize;
在这里,您将它传递给本机函数。默认是ByReference。
你可以找另一个通用的例子here