【问题标题】:va_list type on iOS 64-bit SimulatoriOS 64 位模拟器上的 va_list 类型
【发布时间】:2015-05-19 16:01:40
【问题描述】:

我有以下代码在 64 位 iOS 模拟器上不起作用。它在以下行 EXC_BAD_ACCESS 崩溃 [invocation setArgument:args atIndex:index];

但此代码适用于所有 32 位和 64 位 iPhone 和 iPad 设备,甚至适用于 32 位模拟器。

到目前为止,我发现char* 的强制转换可能是错误的根源。 va_list 似乎是 char* 类型,但在 64 位 iOS 模拟器上除外。

如何避免此错误?这会导致设备出现问题吗?

+(NSInvocation*)invocationWithTarget:(id)target selector:(SEL)aSelector 

retainArguments:(BOOL)retainArguments, ...;
{
    va_list ap;
    va_start(ap, retainArguments);
    char* args = (char*)ap;
    NSMethodSignature* signature = [target methodSignatureForSelector:aSelector];
    NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
    if (retainArguments) {
        [invocation retainArguments];
    }
    [invocation setTarget:target];
    [invocation setSelector:aSelector];
    for (int index = 2; index < [signature numberOfArguments]; index++) {
        const char *type = [signature getArgumentTypeAtIndex:index];
        NSUInteger size, align;
        NSGetSizeAndAlignment(type, &size, &align);
        NSUInteger mod = (NSUInteger)args % align;
        if (mod != 0) {
            args += (align - mod);
        }
        [invocation setArgument:args atIndex:index];
        args += size;
    }
    va_end(ap);
    return invocation;
}

【问题讨论】:

  • 当之无愧地崩溃了。代码的作者故意避开了标准的 va_arg 宏,自己重新实现了,很糟糕。你有一个完美的答案,准确地描述了它应该如何实现。

标签: ios iphone 32bit-64bit variadic-functions


【解决方案1】:

我认为问题出在args += (align - mod);,不知道va_arg 的工作原理,两个版本的编译器可能不同。我建议使用va_arg 而不是自己移动args 的指针。

这样你必须使用Objective-C对象作为参数,因为我们假设它们的类型是id

+ (NSInvocation*)invocationWithTarget:(id)target selector:(SEL)aSelector
                      retainArguments:(BOOL)retainArguments, ...
{
    va_list ap;
    va_start(ap, retainArguments);
    NSMethodSignature* signature = [target methodSignatureForSelector:aSelector];
    NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
    if (retainArguments) {
        [invocation retainArguments];
    }
    [invocation setTarget:target];
    [invocation setSelector:aSelector];
    for (int index = 2; index < [signature numberOfArguments]; index++) {
        id argument = va_arg(ap, id) ;
        [invocation setArgument:&argument atIndex:index];
    }
    va_end(ap);
    return invocation;
}

我相信我们可以更好地使用const char *type = [signature getArgumentTypeAtIndex:index]; 并使用一些方法来解码可以传递给va_arg 的类型,但我没有找到解决方案。

【讨论】:

    猜你喜欢
    • 2014-01-10
    • 2011-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-26
    • 1970-01-01
    • 1970-01-01
    • 2014-04-22
    相关资源
    最近更新 更多