数组中的 JNA 结构内存分配不正确

JNA structure memory allocation in array is incorrect

我的问题是内存分配不正确。我认为是因为位在属性之间移动。

这是本机代码:

typedef struct s_xl_channel_config {
    char                name [32];
    unsigned char       hwType;                               
    unsigned char       hwIndex;                             
    unsigned char       hwChannel;                           
    unsigned short      transceiverType;                     
    unsigned short      transceiverState;                   
    unsigned short      configError;                         
    unsigned char       channelIndex;                       
    unsigned __int64    channelMask;                         
    unsigned int        channelCapabilities;                 
    unsigned int        channelBusCapabilities;                       
    unsigned char       isOnBus;                             
    unsigned int        connectedBusType;                   
    XLbusParams         busParams;
    unsigned int        _doNotUse;                                                                         
    unsigned int        driverVersion;           
    unsigned int        interfaceVersion;                   
    unsigned int        raw_data[10];                   
    unsigned int        serialNumber;
    unsigned int        articleNumber;
    char                transceiverName [32]; 
    unsigned int        specialCabFlags;                     
    unsigned int        dominantTimeout;                     
    unsigned char       dominantRecessiveDelay;             
    unsigned char       recessiveDominantDelay;             
    unsigned char       connectionInfo;                     
    unsigned char       currentlyAvailableTimestamps;         
    unsigned short      minimalSupplyVoltage;                 
    unsigned short      maximalSupplyVoltage;                 
    unsigned int        maximalBaudrate;                     
    unsigned char       fpgaCoreCapabilities;               
    unsigned char       specialDeviceStatus;                 
    unsigned short      channelBusActiveCapabilities;       
    unsigned short      breakOffset;                         
    unsigned short      delimiterOffset;                     
    unsigned int        reserved[3];
} XL_CHANNEL_CONFIG;

我的java代码是这样的:

@FieldOrder ({"name", "hwType", "hwIndex", "hwChannel", "transceiverType",
  "transceiverState", "configError", "channelIndex", "channelMask", 
  "channelCapabilities", "channelBusCapabilities", "isOnBus", "connectedBusType", 
  "busParams",    "_doNotUse", "driverVersion", "interfaceVersion", "raw_data", 
  "serialNumber", "articleNumber", "transceiverName", "specialCabFlags", 
  "dominantTimeout", "dominantRecessiveDelay", "recessiveDominantDelay", 
  "connectionInfo", "currentlyAvailableTimestamps", "minimalSupplyVoltage", 
  "maximalSupplyVoltage", "maximalBaudrate", "fpgaCoreCapabilities", 
  "specialDeviceStatus", "channelBusActiveCapabilities", "breakOffset", 
  "delimiterOffset", "reserved"})
public class XLchannelConfig extends Structure{

    public byte[] name = new byte[32];
    public byte hwType;
    public byte hwIndex;
    public byte hwChannel;
    public short transceiverType;
    public short transceiverState;
    public short configError;
    public byte channelIndex;
    public Nativelong channelMask;
    public int channelCapabilities;
    public int channelBusCapabilities;
    public byte isOnBus;
    public int connectedBusType;
    public XLbusParams busParams= new XLbusParams();
    public int _doNotUse;
    public int driverVersion;
    public int interfaceVersion;
    public int[] raw_data = new int[(10)];
    public int serialNumber;
    public int articleNumber;
    public byte[] transceiverName = new byte[32];
    public int specialCabFlags;
    public int dominantTimeout;
    public byte dominantRecessiveDelay;
    public byte recessiveDominantDelay;
    public byte connectionInfo;
    public byte currentlyAvailableTimestamps;
    public short minimalSupplyVoltage;
    public short maximalSupplyVoltage;
    public int maximalBaudrate;
    public byte fpgaCoreCapabilities;
    public byte specialDeviceStatus;
    public short channelBusActiveCapabilities;
    public short breakOffset;
    public short delimiterOffset;
    public int[] reserved = new int[3];
    
    public XLchannelConfig() {
        super();        
    }

XLchannelConfig class 位于我用 .toArray() 初始化的数组中。 当我输出属性时,我看到值发生了偏移。看起来这些位已经从一个属性转移到下一个属性。我怀疑是数据类型错误,但我无法确定是哪个。

toString 打印出来:

XLchannelConfig [name=Virtual Channel 1               , hwType=1, hwIndex=0, hwChannel=0, transceiverType=0, transceiverState=0, channelIndex=1, channelMask=0, channelCapabilities=458752, channelBusCapabilities=106496, isOnBus=1, connectedBusType=16777216, driverVersion=67830784, interfaceVersion=0, raw_data=[0, 0, 0, 65536, 0, 0, 0, 0, 0, 0], serialNumber=0, articleNumber=536870912, transceiverName=Virtual CAN                    , specialCabFlags=0, dominantTimeout=0, reserved=[0, 0, 1442840576], busParams=XLbusParams [busType=536870912]]

XLchannelConfig [name=irtual Channel 2               , hwType=0, hwIndex=1, hwChannel=22, transceiverType=0, transceiverState=0, channelIndex=0, channelMask=0, channelCapabilities=1792, channelBusCapabilities=16777632, isOnBus=0, connectedBusType=65536, driverVersion=264964, interfaceVersion=0, raw_data=[0, 0, 0, 256, 0, 0, 0, 0, 0, 0], serialNumber=0, articleNumber=1444937728, transceiverName=irtual CAN                    , specialCabFlags=0, dominantTimeout=0, reserved=[0, 0, 0], busParams=XLbusParams [busType=-1591738368]]

症状显示您的映射中多了一个字节。 reserved 字段的最后一个元素包括字节 0x56,它对应于第二个元素中缺少的字母“V”。所以我们需要寻找那个额外的字节。

头文件总线类型最多只能达到 0x100。您的输出的总线类型为 0x20000000,表明错误发生在 XLbusParams 并集之前。它肯定发生在 transcieverName 之前,它显示一个额外的 non-null 字节作为最后一个字符。除了 channelMask(见下文,将是 4 字节偏移量)之外,映射看起来是正确的。

可以解释单个字节的一种可能的不匹配可能是结构字段的对齐。名称占用 32 个字节,然后是三个 1 字节的字段,后面跟着三个 2 字节的字段。这将具有跨越 4 字节或 8 字节边界的 short 字段之一。您可能会考虑使用不同的 JNA 结构对齐方式,例如 Structure.ALIGN_NONE:

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

其他映射评论:

C头中的channelMask字段是一个明确的64位类型(int64),因此应该直接映射到Java的64位long。只有在本机类型为 long 时才应使用 NativeLong 作为映射。这可以是 32 位或 64 位,具体取决于操作系统和位数。这将(可能)under-allocate 4 个字节,但是,可能不是问题。

在 API 中的头文件副本中,我没有看到您包含的 _doNotUse 字段。你确定它应该包括在内吗?这会向映射添加 4 个字节。您确定您复制的头文件与您正在使用的 API 二进制文件的版本匹配吗?

问题的另一个潜在来源是 XLbusParams 类型。 API 表明这是一个具有 int 类型和 32 字节数据的联合。如果您没有正确映射联合(至少是最大的成员)也可能导致偏移。