为什么此代码适用于 iOS 32 位但不适用于 64 位?
Why does this code work on iOS 32 bit but not on 64 bit?
下面的代码从连接到 iOS 设备的乐器接收 MIDI 数据。它在 32 位 iOS 设备上运行良好。在 64 位上,每个事件也会调用回调函数,但是 'pktlist' 中收到的数据是无效的。怎么了?
我在 MidiReadProc
中收到的数据在 64 位设备上总是相同的,这显然是错误的,因为长度通常永远不会是 0:
pktlist^.numPackets = 1
lPacket.MIDItimestamp=$E4FE000100000961
lPacket.length=[=11=]00
lPacket.data[0]=[=11=]
回调函数:
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;
万一它可能与header翻译有关,这里是翻译:
摘自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
C 结构必须在 delphi 中声明为压缩记录。 C 不对齐结构中的字段。
按照评论中的建议,我进一步研究了 CoreMIDI.h
头文件。尽管我从未使用过任何 C 语言,但我确实发现了这一行:#pragma pack(push, 4)
在 MIDIPacket 的定义之上(我现在已将其添加到问题中提取),这清楚地表明应该做什么。
为整个文件设置 {$Align 1}
不是正确的解决方案。相反,只有两条记录(MIDIPacket
和 MIDIPacketList
)应该有 4 字节对齐而不是 8 字节对齐。
下面的代码从连接到 iOS 设备的乐器接收 MIDI 数据。它在 32 位 iOS 设备上运行良好。在 64 位上,每个事件也会调用回调函数,但是 'pktlist' 中收到的数据是无效的。怎么了?
我在 MidiReadProc
中收到的数据在 64 位设备上总是相同的,这显然是错误的,因为长度通常永远不会是 0:
pktlist^.numPackets = 1
lPacket.MIDItimestamp=$E4FE000100000961
lPacket.length=[=11=]00
lPacket.data[0]=[=11=]
回调函数:
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;
万一它可能与header翻译有关,这里是翻译:
摘自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
C 结构必须在 delphi 中声明为压缩记录。 C 不对齐结构中的字段。
按照评论中的建议,我进一步研究了 CoreMIDI.h
头文件。尽管我从未使用过任何 C 语言,但我确实发现了这一行:#pragma pack(push, 4)
在 MIDIPacket 的定义之上(我现在已将其添加到问题中提取),这清楚地表明应该做什么。
为整个文件设置 {$Align 1}
不是正确的解决方案。相反,只有两条记录(MIDIPacket
和 MIDIPacketList
)应该有 4 字节对齐而不是 8 字节对齐。