我正在努力将PTHotKeyLib修改为64位友好,但我在代码中遇到了一个我不确定如何解决的问题。在PTHotKeyCenter中,registerHotKey方法创建一个EventHotKeyID实例,然后将PTHotKey对象填充到id属性中。原始代码使用了很长时间。我根据Apple的64位编程指南将其转换为NSInteger。
- (BOOL)registerHotKey:(PTHotKey *)theHotKey {
OSStatus error;
EventHotKeyID hotKeyID;
EventHotKeyRef carbonHotKey;
NSValue *key = nil;
if ([[self allHotKeys] containsObject:theHotKey])
[self unregisterHotKey:theHotKey];
if (![[theHotKey keyCombo] isValidHotKeyCombo])
return YES;
hotKeyID.signature = kHotKeySignature;
hotKeyID.id = (NSInteger)theHotKey;
... //Rest is not relevant
}
当用户触发热键时,它会调用sendCarbonEvent:方法,该方法将尝试将PTHotKey实例拉出EventHotKeyID。它工作在32位,但是当编译64位时,它给出了“从不同大小的整数转换为指针”警告
- (OSStatus)sendCarbonEvent:(EventRef)event {
OSStatus error;
EventHotKeyID hotKeyID;
SGHotKey *hotKey;
NSAssert(GetEventClass(event) == kEventClassKeyboard, @"Unknown event class");
error = GetEventParameter(event,
kEventParamDirectObject,
typeEventHotKeyID,
nil,
sizeof(EventHotKeyID),
nil,
&hotKeyID);
if (error)
return error;
NSAssert(hotKeyID.signature == kHotKeySignature, @"Invalid hot key id" );
NSAssert(hotKeyID.id != 0, @"Invalid hot key id");
hotKey = (SGHotKey *)hotKeyID.id; // warning: cast to pointer from integer of different size
// Omitting the rest of the code
}
从x86_64切换回i386会删除警告并编译所有内容并正常运行。在x86_64下它会导致崩溃,我不知道如何解决这个问题。有关如何解决它的任何建议?
答案 0 :(得分:4)
建议不要在指针和整数之间进行转换,因为它会导致不可移植的代码。
您正在做的事情导致C99定义为“未定义的行为”。这基本上意味着它可能会起作用,也可能不起作用。 C语言以让你做这样的事情而闻名,因为它隐含地假设你在键入它时知道你在做什么,并且你有精灵37337疯狂的技能和多年的经验来知道什么时候可以安全地做这个,当它不是。
可以肯定地说,这是不安全的时候之一。
来自上下文的问题可能是由于将64位指针转换为int
大小的变量。 Mac OS X 64位ABI就是所谓的LP64
,这意味着long
和pointer
是64位宽,int
是32 -bits宽。因此,简而言之,在您的pointer
到int
之一以及再次投射时,您会将前32位切掉,这恰好非常重要。
查看文档时,id
的类型为UInt32
。所以,简短的回答是你不能将64位指针放入32位大小的整数中。
答案 1 :(得分:1)
经典的答案是你创建一个字典或其他东西,并将键放在id中的字典中,并将指针放在值中,从而避免将实际指针放在32位id中。
但你解决了吗?
答案 2 :(得分:1)
我刚刚遇到与PTHotKeysLib相同的问题。它只出现在x86_64 arch。
为了解决这个问题,我查看了SGHotKeysLib,它不是像上面那样尝试进行转换,而是在64位对象中存储对32位指针的引用。然后当找到32位指针时,它遍历所有64位对象(在本例中为SGHotKey)以找到对32位指针的引用(在本例中为EventHotKeyID。)
进一步参考:https://github.com/secondgear/SGHotKeysLib/blob/master/SGHotKeysLib/SGHotKeyCenter.m
for (SGHotKey *thisHotKey in [self allHotKeys]) {
if ([thisHotKey matchesHotKeyID:hotKeyID]) {
hotKey = thisHotKey;
break;
}
}