gpt4 book ai didi

objective-c - Variadic Function 缓存上次调用的参数列表

转载 作者:太空宇宙 更新时间:2023-11-04 02:28:53 25 4
gpt4 key购买 nike

我使用以下模式为 iOS 库编写了一个带有 c 函数的 Helper 类。有 2 个包装(可变参数)函数,它们最终调用同一个函数,但参数略有不同。想法是设置“默认”属性。

__attribute__((overloadable)) void func1(NSString* _Nonnull format, ...);
__attribute__((overloadable)) void func1(int param1, NSString* _Nonnull format, ...);

然后两者都会调用以下函数:

void prefixAndArguments(int param1, NSString* _Nonnull format, va_list arguments);

实现如下:

__attribute__((overloadable)) void func1(NSString* _Nonnull format, ...)
{
va_list argList;
va_start(argList, format);
prefixAndArguments(0, format, argList);
va_end(argList);
}

__attribute__((overloadable)) void func1(int param1, NSString* _Nonnull format, ...)
{
va_list argList;
va_start(argList, format);
prefixAndArguments(param1, format, argList);
va_end(argList);
}


void prefixAndArguments(NMXLogLevelType logLevel, NSString* _Nullable logPrefix, __strong NSString* _Nonnull format, va_list arguments)
{
// Evaluate input parameters
if (format != nil && [format isKindOfClass:[NSString class]])
{
// Get a reference to the arguments that follow the format parameter
va_list argList;
va_copy(argList, arguments);

int argCount = 0;
NSLog(@"%d",argCount);
while (va_arg(argList, NSObject *))
{
argCount += 1;
}
NSLog(@"%d",argCount);
va_end(argList);

NSMutableString *s;
if (numSpecifiers > argCount)
{
// Perform format string argument substitution, reinstate %% escapes, then print
NSString *debugOutput = [[NSString alloc] initWithFormat:@"Error occured when logging: amount of arguments does not for to the defined format. Callstack:\n%@\n", [NSThread callStackSymbols]];
printf("%s\n", [debugOutput UTF8String]);
s = [[NSMutableString alloc] initWithString:format];
}
else
{
// Perform format string argument substitution, reinstate %% escapes, then print
va_copy(argList, arguments);

// This is were the EXC_BAD_ACCESS will occur!
// Error: Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
s = [[NSMutableString alloc] initWithFormat:format arguments:argList];
[s replaceOccurrencesOfString:@"%%"
withString:@"%%%%"
options:0
range:NSMakeRange(0, [s length])];
NSLog(@"%@",s);
va_end(argList);
}
...
}

我的函数单元测试如下所示(顺序很重要)。

// .. some previous cases, I commented out
XCTAssertNoThrow(NMXLog(@"Simple string output"));
XCTAssertNoThrow(NMXLog(@"2 Placeholders. 0 Vars %@ --- %@"));

当我想使用参数和格式时发生崩溃(使格式变强并没有解决问题,而且似乎不是问题的一部分,见下文):

s = [[NSMutableString alloc] initWithFormat:format arguments:argList];

这是日志:

xctest[28082:1424378] 0
xctest[28082:1424378] --> 1
xctest[28082:1424378] Simple string output
xctest[28082:1424378] 0
xctest[28082:1424378] --> 4

当然,我们不会看到所需的字符串 "2 Placeholders.0 Vars %@ --- %@",因为之前发生过崩溃。

那么,现在的问题是:为什么参数数量现在是 4 而不是 0?由于在第二次调用中没有传递任何参数,是否会在再次立即调用该函数时收集参数?

因此,我开始“再次”调用该函数以确保清除参数列表,尽管正在调用 va_end:

__attribute__((overloadable)) void func1(NSString* _Nonnull format, ...)
{
va_list argList;
va_start(argList, format);
prefixAndArguments(none, nil, format, argList);
va_end(argList);
NSString *obj = nil;
prefixAndArguments(none, nil, obj, nil);
}

现在这确实像一个魅力一样工作(正在清除参数列表并且正在接收所需的输出):

xctest[28411:1453508] 0
xctest[28411:1453508] --> 1
xctest[28411:1453508] Simple string output
xctest[28411:1453508] 0
xctest[28411:1453508] --> 1
Error occured when logging: amount of arguments does not for to the defined format. Callstack: ....
xctest[28411:1453508] 2 Placeholders. 0 Vars %@ --- %@

最后是我的问题:

这种行为的原因是什么,我该如何避免?有没有比用“无”参数“愚蠢地”第二次调用函数来清除它们更好的方法来解决这个问题?附言我尽量不使用宏,因为我认为它们比 c 函数更容易出错。看到这个线程:Macro vs Function in C

最佳答案

您似乎对可变参数函数有一些误解,例如这种计算可变参数的方法:

        while (va_arg(argList, NSObject *))
{
argCount += 1;
}

该代码假定变量参数至少有一个成员,所有成员都是 NSObject * 类型,并且该列表将由该类型的空指针终止。系统不能保证这些,如果不满足这些假设,则一个或多个 va_arg() 调用的行为将是未定义的。

在实践中,您可能可以摆脱作为其他类型指针的实际参数(尽管形式上,在这种情况下行为仍然是未定义的)。但是,如果参数可能具有非指针类型,那么计算它们的方法就完全失效了。更重要的是,您的测试用例似乎假定系统 将提供尾随 NULL 参数,但这绝不是保证。

如果您的函数依赖于由 NULL 参数指示的可变参数列表的末尾,那么它依赖于调用者 来提供一个。很可能在您的参数列表中没有空终止导致您所询问的行为。

关于objective-c - Variadic Function 缓存上次调用的参数列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46790419/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com