我有一个奇怪的问题,设置一个NSInvocation的参数,其结构包含一个未对齐的double或任何64位类型(我在结构的开头用一个char来抵消它)。问题是在设置参数后会清除一些字节。在ARM7上会出现此问题,但在iOS模拟器中不会出现此问题。
我正在使用LLVM 3.0和Xcode 4.2
这是我的代码和测试结果:
NSInvocation的+ Extension.h
@interface NSInvocation (Extension)
+ (NSInvocation*) invocationWithTarget: (id)aTarget
selector: (SEL)aSelector
retainArguments: (BOOL)aRetainArguments, ...;
- (void) setArguments: (va_list)aArgList;
- (void) setArguments: (va_list)aArgList atIndex: (NSInteger)aIndex;
@end // NSInvocation (Extension)
NSInvocation的+ Extension.m
#import <objc/runtime.h>
#import "NSInvocation+Extension.h"
@implementation NSInvocation (Extension)
+ (NSInvocation*) invocationWithTarget: (id)aTarget
selector: (SEL)aSelector
retainArguments: (BOOL)aRetainArguments, ...
{
NSMethodSignature* signature = [aTarget methodSignatureForSelector: aSelector];
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: signature];
if (aRetainArguments)
{
[invocation retainArguments];
}
[invocation setTarget: aTarget];
[invocation setSelector: aSelector];
va_list argList;
va_start(argList, aRetainArguments);
[invocation setArguments: argList];
va_end(argList);
return invocation;
}
- (void) setArguments: (va_list)aArgList
{
[self setArguments: aArgList atIndex: 0];
}
- (void) setArguments: (va_list)aArgList atIndex: (NSInteger)aIndex
{
// Arguments are aligned on machine word boundaries
const NSUInteger KOffset = sizeof(size_t) - 1;
UInt8* argPtr = (UInt8*)aArgList;
NSMethodSignature* signature = [self methodSignature];
// Indices 0 and 1 indicate the hidden arguments self and _cmd respectively.
for (int index = aIndex + 2; index < [signature numberOfArguments]; ++index)
{
const char* type = [signature getArgumentTypeAtIndex: index];
NSUInteger size = 0;
NSGetSizeAndAlignment(type, &size, NULL);
[self setArgument: argPtr atIndex: index];
argPtr += (size + KOffset) & ~KOffset;
}
}
@end // NSInvocation (Extension)
声明要调用的方法和数据结构
- (void) arg1: (char)aArg1 arg2: (char)aArg2 arg3: (TEST)aArg3 arg4: (char)aArg4;
typedef struct test {
char c;
double s;
char t;
void* b;
char tu;
} TEST;
致电代码
TEST df = { 'A', 12345678.0, 'B', (void*)2, 'C' };
char buf[100] = {0};
NSInvocation* ik = [NSInvocation invocationWithTarget: self selector: @selector(arg1:arg2:arg3:arg4:) retainArguments: NO, '1', '2', df, '3'];
[ik getArgument: &buf atIndex: 4];
ARM7上buf的内容(字节8,9,10和11设置为零,这搞砸了双值)
41 00 00 00 00 00 00 00 29 8C 67 41 42 00 00 00 02 00 00 00 43 00 00 00
i386模拟器上的buf内容(如预期的那样)
41 00 00 00 00 00 00 C0 29 8C 67 41 42 00 00 00 02 00 00 00 43 00 00 00
答案 0 :(得分:2)
首先想到的是你真的必须使用va_arg来访问可变参数列表中的连续参数。你无法假设参数是像你一样安排在一个很好的连续内存中。首先,ARM ABI说前四个参数是在寄存器中传递的。
va_list不一定只是一个指针,它是一个不透明的类型。你对uint8_t *的演员几乎肯定无效。