JNA中结构体的内存分配不匹配

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

JNA memory allocation of Structure does not match

问题

本地代码中的结构体:
```c
struct s_xl_daio_data {  /* 32字节 */
         unsigned short    flags;                 // 2
         unsigned int      timestamp_correction;  // 4
         unsigned char     mask_digital;          // 1
         unsigned char     value_digital;         // 1
         unsigned char     mask_analog;           // 1
         unsigned char     reserved0;             // 1
         unsigned short    value_analog[4];       // 8
         unsigned int      pwm_frequency;         // 4
         unsigned short    pwm_value;             // 2
         unsigned int      reserved1;             // 4
         unsigned int      reserved2;             // 4
};

我的Java类:

@FieldOrder ({"flags", "timestamp_correction", "mask_digital", 
"value_digital", "mask_analog", "reserved0", "value_analog",
"pwm_frequency", "pwm_value", "reserved1", "reserved2"})
public class s_xl_daio_data extends Structure {	
    public short    flags;                 // 2
    public int      timestamp_correction;  // 4
    public byte     mask_digital;          // 1
    public byte     value_digital;         // 1
    public byte     mask_analog;           // 1
    public byte     reserved0;             // 1
    public short[]    value_analog= new short[4];       // 8
    public int      pwm_frequency;         // 4
    public short    pwm_value;             // 2
    public int      reserved1;             // 4
    public int      reserved2;             // 4

	public s_xl_daio_data() {
		super();
	}
}

本地结构体的大小为32字节。如果我使用Structure的.size()操作打印出结构体的大小,结果是36字节。

那4个额外的字节是什么?


<details>
<summary>英文:</summary>

the struct in my native code:

struct s_xl_daio_data { /* 32 Bytes */
unsigned short flags; // 2
unsigned int timestamp_correction; // 4
unsigned char mask_digital; // 1
unsigned char value_digital; // 1
unsigned char mask_analog; // 1
unsigned char reserved0; // 1
unsigned short value_analog[4]; // 8
unsigned int pwm_frequency; // 4
unsigned short pwm_value; // 2
unsigned int reserved1; // 4
unsigned int reserved2; // 4
};

my Java class:

@FieldOrder ({"flags", "timestamp_correction", "mask_digital",
"value_digital", "mask_analog", "reserved0", "value_analog",
"pwm_frequency", "pwm_value", "reserved1", "reserved2"})
public class s_xl_daio_data extends Structure {
public short flags; // 2
public int timestamp_correction; // 4
public byte mask_digital; // 1
public byte value_digital; // 1
public byte mask_analog; // 1
public byte reserved0; // 1
public short[] value_analog= new short[4]; // 8
public int pwm_frequency; // 4
public short pwm_value; // 2
public int reserved1; // 4
public int reserved2; // 4

public s_xl_daio_data() {
	super();
}

}


The native Struct is 32 Bytes. If I print out the size of the struct with the `.size()`operation from Structure it is 36 Bytes.

What are the 4 additional bytes?

</details>


# 答案1
**得分**: 1

映射是正确的,但是[默认结构对齐][1]在JNA中创建了额外的填充,JNA假定使用默认值,除非另有说明。

您可以确认这一点并调试将来的结构大小/对齐不匹配问题,方法是使用默认的`Structure`类的`toString()`方法。它会打印每个字段的偏移和值,这样您就可以查找偏移与您预期不匹配的情况。

```java
s_xl_daio_data foo = new s_xl_daio_data();
System.out.println(foo.toString());

在我的系统上检查该代码的输出显示,在第一个short之后有两个额外的字节,因为int timestamp_correction必须从4字节边界开始(0x4而不是0x2):

short flags@0x0=0x00
int timestamp_correction@0x4=0x0000

在最后一个short之后还有两个额外的字节,因为int reserved1必须从4字节边界开始(0x1C而不是0x1A):

short pwm_value@0x18=0x00
int reserved1@0x1C=0x0000

默认的对齐通常适用于系统DLL,这些DLL在许多情况下会考虑结构对齐并使用显式填充字段。然而,有时其他DLL可能不需要对齐,在这种情况下,在实例化结构时您可以在JNA中指定这一点。

public s_xl_daio_data() {
    super(Structure.ALIGN_NONE);
}

通过使用前面提到的相同toString()方法,确认这是否为您提供了预期的数据在适当的字段中将会很有用。

英文:

The mappings are correct, but default structure alignments are creating extra padding in JNA, which assumes defaults unless told otherwise.

A way for you to confirm this and debug future structure size/alignment mismatches is to use the default Structure class toString() method. It prints each field's offset and value, so you can look for the misalignment of the offsets with your expectations.

s_xl_daio_data foo = new s_xl_daio_data();
System.out.println(foo.toString());

Inspecting the output of that code on my system shows two extra bytes after the first short because int timestamp_correction must start on a 4-byte boundary (0x4 rather than 0x2):

short flags@0x0=0x00
int timestamp_correction@0x4=0x0000

and two more extra bytes after the last short because int reserved1 must start on a 4-byte boundary (0x1C rather than 0x1A):

short pwm_value@0x18=0x00
int reserved1@0x1C=0x0000

The default alignment often works with system DLLs which in many cases take structure alignment into account with explicit padding fields. However, sometimes other DLLs require no alignment, in which case you would specify this in JNA when instantiating the structure.

public s_xl_daio_data() {
    super(Structure.ALIGN_NONE);
}

It would be useful to confirm this is giving you the expected data in the appropriate fields using the same toString() noted earlier.

huangapple
  • 本文由 发表于 2020年9月17日 22:01:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/63939781.html
匿名

发表评论

匿名网友

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

确定