JNA中的结构中的结构数组

huangapple go评论62阅读模式
英文:

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 &lt; channel.length; i++) {
			channel[i]= new ChannelConfig();
		}
	}

	@Override
	protected List&lt;String&gt; getFieldOrder() {
	    return Arrays.asList(new String[] { &quot;dllVersion&quot;, &quot;channelCount&quot;, &quot;reserved&quot; });
	}

    //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(&quot;DriverConfig Status: &quot; + 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&#39;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>



huangapple
  • 本文由 发表于 2020年9月7日 20:21:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/63777532.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定