结构的JNA内存分配不匹配

问题描述

本机代码中的结构:

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

我的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个字节是什么?

解决方法

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

一种确认并调试未来结构尺寸/对齐不匹配的方法是使用默认的StructuretoString()方法。它会打印每个字段的偏移量和值,因此您可以查找与期望值不同的偏移量。

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(),确认这是否在适当的字段中为您提供了预期的数据。