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

问题描述

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

这是本机代码

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类位于我用.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,65536,0],serialNumber=0,articleNumber=536870912,transceiverName=Virtual CAN,specialCabFlags=0,dominantTimeout=0,reserved=[0,1442840576],busParams=XLbusParams [busType=536870912]]

XLchannelConfig [name=irtual Channel 2,hwType=0,hwIndex=1,hwChannel=22,channelIndex=0,channelCapabilities=1792,channelBusCapabilities=16777632,isOnBus=0,connectedBusType=65536,driverVersion=264964,256,articleNumber=1444937728,transceiverName=irtual CAN,busParams=XLbusParams [busType=-1591738368]]

解决方法

症状表明映射中有一个额外的单字节。 def _configureOutputFilename(self,filename): """ generates filename appends timeseries file extension if necessary prepends sample directory if used in stochastic """ assert not os.path.isabs(filename),filename if not os.path.splitext(filename)[1]: filename += ".tss" if hasattr(self._userModel,"nrSamples"): filename = os.path.join(str(self._userModel.currentSampleNumber()),filename) return filename 字段的最后一个元素包括字节reserved,它对应于第二个元素中缺少的字母“ V”。因此,我们需要寻找额外的字节。

头文件总线类型最多只能达到0x56。您的输出的总线类型为0x100,表明错误在0x20000000联合之前发生。它肯定发生在XLbusParams之前,后者显示一个额外的非空字节作为最后一个字符。除了transcieverName(如下所述,偏移量为4个字节)之外,映射看起来是正确的。

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

short

其他映射注释:

C头中的public XLchannelConfig() { super(Structure.ALIGN_NONE); } 字段是显式的64位类型(channelMask),因此应直接映射到Java的64位int64。仅当本机类型为long时,才应使用NativeLong作为映射。可以是32位,也可以是64位,具体取决于操作系统和位。但是,这可能会分配不足4个字节,这可能不是问题。

在API头文件的副本中,看不到您包含的long字段。您确定应将其包括在内吗?这会向映射添加4个字节。您确定复制的头文件与您使用的API二进制文件的版本匹配吗?

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