【问题标题】:How do I define a macro with variadic method in objective-C?如何在 Objective-C 中使用可变参数方法定义宏?
【发布时间】:2014-02-26 01:19:16
【问题描述】:

我试图调用的方法是;

- (void)addLogWithLevel:(MDCLogLevel)logLevel logContent:(NSString *)logContent, ...
{
    va_list args;
    va_start(args, logContent);
    NSString *message = [[NSString alloc] initWithFormat:logContent
                                               arguments:args];
    va_end(args);
    MDCLog *log = [MDCLog logWithContent:message content:logLevel];
    [self.deviceLogs addObject:log];
}

我已将宏定义为;

#define MDCLogDebug(format, ...) [[MDCLogController sharedController] addLogWithLevel:MDCLogLevelDebug logContent:(__VA_ARGS__)];

我尝试了这个宏的各种格式,但似乎没有任何效果。

如果我要打电话;

MDCLogDebug(@"Test:%@", @"Hey");

我在控制台中看到的只是;

我哪里出错了?我是使用 Variadic 方法的新手,我的 C 不是那么好!

【问题讨论】:

    标签: ios objective-c macros variadic


    【解决方案1】:

    实际上,您的问题与 Objective-C 并没有直接关系,而是与 C 本身有关,因为宏是普通的 C 预处理器指令。

    在宏中,__VA_ARGS__ 表示放置的参数,而不是 ...

    因此,在您调用 MDCLogDebug(@"Test:%@", @"Hey") 时,format 参数是 @"Test:%@"__VA_ARGS__ 表示之后的其余参数,即在您的情况下只是 @"Hey"

    如果你想将@"Test:%@"@"Hey" 作为参数传递给logContent:,你必须明确告诉它,使用:

    #define MDCLogDebug(format, ...) [[MDCLogController sharedController] addLogWithLevel:MDCLogLevelDebug logContent:format, __VA_ARGS__]
    

    注意:更好的解决方案是在__VA_ARGS__ 之前使用## 前缀,这样如果__VA_ARGS__ 为空(即如果您只传递format争论,但之后什么都没有,比如MDCLogDebug(@"Foo")):

    #define MDCLogDebug(format, ...) [[MDCLogController sharedController] \
                                      addLogWithLevel:MDCLogLevelDebug \
                                           logContent:format, ## __VA_ARGS__]
    

    (注意:我在上面最后一个宏定义中使用了反斜杠,以允许将宏写在多行上,而不是写在一个大长行上)

    欲了解更多信息,see the official GCC documentation about Variadic Macros here

    【讨论】:

    • 您好,感谢您的回复。将行更正为#define MDCLogDebug(format, ...) [[MDCLogController sharedController] addLogWithLevel:MDCLogLevelDebug logContent:(format, ##__VA_ARGS__)]; 也不能解决问题。我仍然在希望看到“Test:Hey”的控制台中看到“Hey”。宏应该完全像 NSLog 一样工作。 NSString *message 似乎没有正确地将格式和参数放在一起?
    • 我认为logContent:(format, __VA_ARGS__) 中的括号是错误的。应该是#define MDCLogDebug(format, ...) [[MDCLogController sharedController] addLogWithLevel:MDCLogLevelDebug logContent:format, ##__VA_ARGS__]。而且你不应该在宏定义中附加分号!
    • 马丁是正确的。使用括号,有一个方法参数,它是使用逗号运算符的表达式,而不是方法参数的列表。因此,每个子表达式都按顺序计算,但整个表达式采用最后一个子表达式的值。并且分号将在宏使用站点提供,就像问题所示,所以它不应该在宏中。将它放在宏中可能会搞砸if-else 语句。
    • @MartinR 现在完美运行,感谢您的解释!
    • 我编辑了我的答案以删除括号(我没有尝试我的代码并直接在 SO 上即时编写)。感谢@MartinR 的评论。还删除了我复制/粘贴的分号,甚至没有注意到,而正如其他人所解释的,您不应该添加到宏本身。 (PS:如果这个答案解决了您的问题,别忘了在 SO 上将其标记为已接受,以告诉其他人您的问题已经得到解决)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 2014-08-03
    • 1970-01-01
    • 2012-09-05
    相关资源
    最近更新 更多