问题
I'm working on modifying the PTHotKeyLib to be 64-bit friendly, but I've run into an issue in the code that I'm not sure how to get around. In PTHotKeyCenter, the registerHotKey method create an EventHotKeyID instance and then stuffs the of PTHotKey object into the id attribute. The original code used a long. I converted it to NSInteger per Apple's 64 bit programming guide.
- (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
}
When a user triggers the hot key, it calls the sendCarbonEvent: method that will try to pull the PTHotKey instance out of EventHotKeyID. It worked in 32-bit land, but when compiling against 64-bit, it gives a "cast to pointer from integer of different size" warning
- (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
}
Switching from x86_64 back to i386 removes the warning and everything compiled and runs properly. Under x86_64 it causes a crasher, and I'm not sure how to get around that issue. Any suggestions on how to resolve it?
回答1:
Casting between pointers and integers is not recommended because it results in non-portable code.
What you are doing results in what C99 defines as "undefined behavior". This basically means it might work, and it might not. The C language is famous for letting you do things like this because it implicitly assumes that you knew what you were doing when you typed it in and that you have the wizardly 37337 mad skillz and years of experience to know when it's safe to do something like this and when it's not.
It's safe to say this this is one of those times when it was not safe to do.
The problem, from context, is probably due to casting a 64-bit pointer in to an int
sized variable. Mac OS X 64-bit ABI is what is known as LP64
, which means that long
s and pointer
s are 64-bits wide, and that int
s are 32-bits wide. So, in short, during one of your pointer
to int
and back again castings, you chopped off the top 32 bits, which just so happened to be really important.
Looking at the docs, the type for id
is UInt32
. So, the short answer is you can't put 64-bit pointers in to 32-bit sized integers.
回答2:
The classic answer is you make a dictionary or something, and put the key to the dictionary in the id, and the pointer in the value, thus avoiding having the actual pointer in the 32bit id.
But have you solved it yet?
回答3:
I just ran into this same exact problem with PTHotKeysLib. It only shows up in the x86_64 arch.
To solve, I looked at SGHotKeysLib, which instead of trying to do the cast as above, instead stores a reference to the 32 bit pointer in the 64 bit object. Then when the 32 bit pointer is found, it loops through all the 64 bit objects (in this case SGHotKey) to find the reference to the 32 bit pointer (in this case EventHotKeyID.)
Further reference: https://github.com/secondgear/SGHotKeysLib/blob/master/SGHotKeysLib/SGHotKeyCenter.m
for (SGHotKey *thisHotKey in [self allHotKeys]) {
if ([thisHotKey matchesHotKeyID:hotKeyID]) {
hotKey = thisHotKey;
break;
}
}
来源:https://stackoverflow.com/questions/1186766/resolving-cast-to-pointer-from-integer-of-different-size-error-in-64-bit-convers