为什么我对`stringWithFormat:`的调用会导致程序崩溃?

时间:2013-12-05 02:44:22

标签: objective-c macos nsstring osx-mavericks

我正在尝试使用以下格式字符串,但这会导致EXC_BAD_ACCESS尝试从0xCobjc_msgSend处读取。 Clang告诉我格式字符串是有效的(除了它有未使用的参数)。这是一个SSCCE:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        NSString* segment = nil;
        NSString* base = @"ebp";
        char sign = '+';
        long long displacement = 12;
        long long absDisplacement = llabs(displacement);
        NSString* offset = nil;
        NSString* nsSize = @"dword";

        NSString* r = [NSString stringWithFormat:@"%7$@ ptr [%2$@ %3$c %5$lli]", segment, base, sign, displacement, absDisplacement, offset, nsSize];
        NSLog(@"%@", r);
    }
    return 0;
}

我不使用格式字符串的所有参数,因为要从16种可能性中选择特定格式,并且所有格式字符串中都不使用某些参数(此特定格式字符串忽略参数1,4和6)。类型如下:

  1. NSString*
  2. NSString*
  3. char
  4. long long
  5. long long
  6. NSString*
  7. NSString*
  8. 据我所知,我所有的格式说明符都尊重这一点。没有打印对象参数为nil,即使这是stringWithFormat:支持的方案。

    那么我做错了什么?

    编辑更改displacement的值会更改错误的读取地址,但我看不清楚原因。格式字符串对我来说仍然是正确的...我无法弄清楚模式:12次崩溃,12次崩溃,0次爆炸时13次崩溃,0次爆炸造成14次崩溃,0次爆炸造成15次崩溃,16次崩溃造成16次崩溃,导致程序失败退出状态为零而不通过NSLog

2 个答案:

答案 0 :(得分:4)

答案是在手册页(强调我的):

  

可选字段,由十进制数字字符串后跟a组成   $,指定要访问的下一个参数。如果不是这个字段   提供,访问的最后一个参数后面的参数将是   用过的。参数从1开始编号。如果未访问   格式字符串中的参数散布在那些参数中   访问结果将是不确定的

编辑:这是剥离未使用参数的工作版本:

#import <Foundation/Foundation.h>

int main(int argc, char *argv[]) {
    @autoreleasepool {
        NSString* segment = nil;
        NSString* base = @"ebp";
        char sign = '+';
        long long displacement = 12;
        long long absDisplacement = llabs(displacement);
        NSString* offset = nil;
        NSString* nsSize = @"dword";

        NSString* r = [NSString stringWithFormat:@"%4$@ ptr [%1$@ %2$c %3$lli]", base, sign, absDisplacement, nsSize];
        NSLog(@"%@", r);
    }
}

答案 1 :(得分:1)

您不能在格式字符串中省略某些参数。这是因为C varargs的工作方式 - 参数列表基本上只是一个不加选择的字节流。为了读取参数5,函数需要知道参数1-4的类型,以确定参数5在列表中的位置。