Search code examples
javastructurejnaallocation

JNA memory allocation of Structure does not match


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?


Solution

  • 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.