为什么这段代码适用于iOS 32位但不适用于64位?

时间:2016-06-01 15:08:01

标签: ios delphi xcode7.3 ios9.3 delphi-10.1-berlin

以下代码从连接到iOS设备的乐器接收MIDI数据。它在32位iOS设备上运行良好。在64位上,还为每个事件调用回调函数,但在'pktlist'中接收的数据无效。有什么问题?

我在MidiReadProc中收到的数据在64位设备上始终是相同的,并且显然是错误的,因为长度通常不会为0:

pktlist^.numPackets = 1
lPacket.MIDItimestamp=$E4FE000100000961
lPacket.length=$0000
lPacket.data[0]=$00

回调功能:

procedure MidiReadProc(pktlist: MIDIPacketListRef; refCon, connRefCon: Pointer); cdecl;
var
  lPacket: MIDIPacket;
  lPacketRef: MIDIPacketRef;
  j: Integer;
  lPtr: ^Byte;
begin
  lPacketRef := MIDIPacketRef(@(pktlist^.Packet[0]));
  for j := 0 to pktlist^.numPackets-1 do
  begin
    lPacket := lPacketRef^;
    if (lPacket.length > 0) and (lPacket.data[0] <> $F0) then
      //handle data here

    //translation of the MIDIPacketNext Macro:
    lPtr := @lPacketRef^.data[lPacketRef^.length];
    lPacketRef := MIDIPacketRef((UInt64(lPtr) + 3) and (not 3));
  end;
end;

如果它可能与标题翻译有关,这里是翻译:

从CoreMIDI.h中提取:

typedef UInt64 MIDITimeStamp;

#pragma pack(push, 4)
struct MIDIPacket
{
    MIDITimeStamp       timeStamp;
    UInt16              length;
    Byte                data[256];
};
typedef struct MIDIPacket           MIDIPacket;

struct MIDIPacketList
{
    UInt32              numPackets; 
    MIDIPacket          packet[1];
};
typedef struct MIDIPacketList MIDIPacketList;
#pragma pack(pop)

typedef void
(*MIDIReadProc)(const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon);


#if TARGET_CPU_ARM || TARGET_CPU_ARM64
// MIDIPacket must be 4-byte aligned
#define MIDIPacketNext(pkt) ((MIDIPacket *)(((uintptr_t)(&(pkt)->data[(pkt)->length]) + 3) & ~3))

从CoreMIDI.pas中提取(CoreMIDI.h的翻译由Pavel Jiri Strnad和is available here制作):

MIDITimeStamp = UInt64;

MIDIPacket = record
   timeStamp: MIDITimeStamp;
   length: UInt16;
   data: array [0..255] of Byte;
end;
MIDIPacketRef = ^MIDIPacket;

MIDIPacketList = record
   numPackets: UInt32;
   packet: array [0..0] of MIDIPacket;
end;
MIDIPacketListRef = ^MIDIPacketList;

MIDIReadProc = procedure (pktlist: MIDIPacketListRef; readProcRefCon: pointer; srcConnRefCon: pointer); cdecl;

更新

正如David在评论中所建议的,这里是记录的字段偏移:

MIDIPacketList抵消:

64 bit Align 8: numPackets=0 packet=8 <- this was the one causing problems
64 bit Align 1: numPackets=0 packet=4
32 bit Align 8: numPackets=0 packet=4
32 bit Align 1: numPackets=0 packet=4

MIDIPacket抵消:

64 bit Align 8: timeStamp=0 length=8 data=10
64 bit Align 1: timeStamp=0 length=8 data=10
32 bit Align 8: timeStamp=0 length=8 data=10
32 bit Align 1: timeStamp=0 length=8 data=10

2 个答案:

答案 0 :(得分:1)

正如评论中所建议的那样,我进一步研究了CoreMIDI.h头文件。虽然我从未使用过任何C语言,但我确实发现了这一行:{MID}之前定义的#pragma pack(push, 4)(我现在已将其添加到问题中提取),这清楚地表明了应该做什么。

为整个文件设置{$Align 1}不是正确的解决方案。相反,只有两个记录(MIDIPacketMIDIPacketList)应该有4个字节的对齐,而不是8个字节的对齐。

答案 1 :(得分:-1)

必须在delphi中将C结构声明为打包记录。 C不对齐struct的字段。