结构的 JNA 内存分配不匹配

JNA memory allocation of Structure does not match

我本机代码中的结构:

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
};

我的Javaclass:

@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();
    }
}

原生 Struct 是 32 字节。如果我使用 Structure 中的 .size() 操作打印出结构的大小,它是 36 字节。

额外的 4 个字节是什么?

映射是正确的,但是 default structure alignments 在 JNA 中创建了额外的填充,除非另有说明,否则它采用默认值。

确认这一点并调试未来结构 size/alignment 不匹配的一种方法是使用默认的 Structure class toString() 方法。它打印每个字段的偏移量和值,因此您可以查找偏移量是否与您的预期不一致。

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() 在适当的字段中为您提供预期数据会很有用。