英文:
Array of structures in a structure in JNA
问题
我的原生代码是:
typedef struct driver_config {
unsigned int dllVersion;
unsigned int channelCount;
unsigned int reserved[10];
ChannelConfig channel[64];
} DriverConfig;
在Java中,我的类如下所示:
public class DriverConfig extends Structure {
public int dllVersion;
public int channelCount;
public int[] reserved= new int[10];
ChannelConfig[] channel = new ChannelConfig[64];
public DriverConfig() {
super();
init();
}
private void init() {
for (int i = 0; i < channel.length; i++) {
channel[i]= new ChannelConfig();
}
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "dllVersion", "channelCount", "reserved" });
}
//toString()...
}
方法声明如下:
int getDriverConfig(DriverConfig driverConfig);
我尝试以以下方式访问该方法:
DriverConfig driverConfig = new DriverConfig();
status = dll.INSTANCE.getDriverConfig(driverConfig);
System.out.println("DriverConfig Status: " + status);
System.out.println(driverConfig.toString());
如果将channel.length
替换为小于50,则数组会正确初始化,但使用channel.length
时它不起作用。它甚至没有显示任何错误,什么都没有显示。
英文:
My native code is
typedef struct driver_config {
unsigned int dllVersion;
unsigned int channelCount;
unsigned int reserved[10];
ChannelConfig channel[64];
} DriverConfig;
In Java my class looks like this
public class DriverConfig extends Structure {
public int dllVersion;
public int channelCount;
public int[] reserved= new int[10];
ChannelConfig[] channel = new ChannelConfig[64];
public DriverConfig() {
super();
init();
}
private void init() {
for (int i = 0; i < channel.length; i++) {
channel[i]= new ChannelConfig();
}
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "dllVersion", "channelCount", "reserved" });
}
//toString()...
}
The method declaration is
int getDriverConfig(DriverConfig driverConfig);
I tried to access the method like this
DriverConfig driverConfig = new DriverConfig();
status = dll.INSTANCE.getDriverConfig(driverConfig);
System.out.println("DriverConfig Status: " + status);
System.out.println(driverConfig.toString());
If channel.length
is replaced with less then 50 the array is initialized correctly but with channel.length
it did not work. It even did not show any error just nothing.
答案1
得分: 1
// 以下是翻译后的内容:
// 注意:代码部分不需要翻译,只翻译注释和说明部分。
Your `getFieldOrder()` 数组未包含结构体的最后一个元素(`channel`)。从你的注释中可以看出,你尝试过这样做,但因为你未将其声明为 `public`,所以出现了错误。结构体的所有元素必须在 `FieldOrder` 中列出,并且还必须声明为 `public`,以便可以通过反射找到它们。
另外,对于使用 JNA 5.x(你应该在使用)的情况,推荐使用 `@FieldOrder` 注解。
你还没有为 `ChannelConfig` 进行映射,但你的问题标题和[与你的结构相匹配的此 API 链接][1]表明它是一个嵌套的结构体数组。结构体数组必须使用连续的内存进行分配,可以通过直接分配本机内存(`new Memory()`)(需要知道结构体的大小),或者使用 `Structure.toArray()` 来实现。就像你所做的循环分配一样,每个新结构体分配的内存可能/很可能不连续地位于本机内存中。鉴于你说对某些值似乎有效,你可能在连续分配方面得到了一些幸运,但是你的行为肯定是未定义的。
因此,你的结构体映射应如下所示:
```java
@FieldOrder({"dllVersion", "channelCount", "reserved", "channel"})
public class DriverConfig extends Structure {
public int dllVersion;
public int channelCount;
public int[] reserved = new int[10];
public ChannelConfig[] channel = (ChannelConfig[]) new ChannelConfig().toArray(64);
}
<details>
<summary>英文:</summary>
Your `getFieldOrder()` array does not include the last element (`channel`) of your structure. I see in your comments that you attempted to do this but received an error because you have not declared it `public`. All elements of your structure must be listed in the `FieldOrder` and also declared `public` so they can be found with reflection.
Also, with JNA 5.x (which you should be using) the `@FieldOrder` annotation is preferred.
You haven't identified the mapping for `ChannelConfig`, but your question title and [this API link matching your structure][1] indicate that it is a nested structure array. Structure arrays must be allocated using contiguous memory, either by directly allocating the native memory (`new Memory()`) which requires knowing the structure size, or by using `Structure.toArray()`. Allocating in a loop as you have done will end up with memory for each new structure allocated at possibly/probably non-contiguous locations in native memory. Given that you state that it appears to work for some values, you might be getting lucky with contiguous allocations, but your behavior is certainly undefined.
Your structure mapping should therefore be:
@FieldOrder ({"dllVersion", "channelCount", "reserved", "channel"})
public class DriverConfig extends Structure {
public int dllVersion;
public int channelCount;
public int[] reserved= new int[10];
public ChannelConfig[] channel = (ChannelConfig[]) new ChannelConfig().toArray(64);
}
[1]: https://assets.vector.com/cms/content/products/XL_Driver_Library/Docs/XL_Driver_Library_Manual_EN.pdf
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论