【问题标题】:Conditional macro expansion条件宏扩展
【发布时间】:2011-03-03 03:40:50
【问题描述】:

请注意:这是一个奇怪的问题。

我有一些非常有用的宏,我喜欢用它们来简化一些日志记录。例如我可以做Log(@"My message with arguments: %@, %@, %@", @"arg1", @"arg2", @"arg3"),这将扩展为一个更复杂的方法调用,包括self_cmd__FILE____LINE__等,这样我就可以轻松跟踪事情的位置正在被记录。这很好用。

现在我想扩展我的宏,使其不仅适用于 Objective-C 方法,而且适用于通用 C 函数。问题在于宏扩展中的self_cmd 部分。这两个参数在 C 函数中不存在。理想情况下,我希望能够在 C 函数中使用同一组宏,但我遇到了问题。当我使用(例如)我的 Log() 宏时,我收到关于 self_cmd 未声明的编译器警告(这完全有道理)。

我的第一个想法是(在我的宏中)执行以下操作:

if (thisFunctionIsACFunction) {
  DoLogging(nil, nil, format, ##__VA_ARGS__);
} else {
  DoLogging(self, _cmd, format, ##__VA_ARGS__);
}

这仍然会产生编译器警告,因为整个 if() 语句被替换为宏,导致 self_cmd 关键字出错(即使它们在函数执行期间永远不会被执行)。

我的下一个想法是做这样的事情(在我的宏中):

if (thisFunctionIsACFunction) {
  #define SELF nil
  #define CMD nil
} else {
  #define SELF self
  #define CMD _cmd
}
DoLogging(SELF, CMD, format, ##__VA_ARGS__);

不幸的是,这不起作用。我在第一个 #define 上收到“错误:'#' 后面没有宏参数”。

我的另一个想法是创建第二组宏,专门用于 C 函数。这散发着一股糟糕的代码味道,我真的不想这样做。

有什么方法可以在 Objective-C 方法和 C 函数中使用相同的宏集,并且如果宏在 Objective-C 方法中,则仅引用 self_cmd

编辑更多信息:

thisFunctionIsACFunction 以非常基本的方式确定(我绝对愿意接受改进和建议)。基本上是这样的:

BOOL thisFunctionIsACFunction == (__PRETTY_FUNCTION__[0] != '-' && __PRETTY_FUNCTION__[0] != '+');

它依赖于编译器的行为,在 Objective-C 对象上添加“-”或“+”实例和类方法。其他任何东西都必须是 C 函数(因为 C 函数的名称不能以“-”或“+”开头)。

我了解此检查在技术上是运行时检查,因为 __PRETTY_FUNCTION__ 被替换为 char*,这可能是我请求帮助的主要障碍。

【问题讨论】:

  • 你是怎么想出thisFunctionIsACFunction的?
  • @Artelius 编辑问题并提供更多信息

标签: c objective-c macros conditional


【解决方案1】:

您可以使用某种宏条件:

#ifndef OBJECTIVE_C
  #define self 0
  #define _cmd ""
#endif

我不太确定您应该如何定义 self_cmd,这些只是猜测。

我不确定是否有预定义的宏可以检查您是否在 Objective C 中编译,因此您可能需要手动定义 OBJECTIVE_C 作为构建的一部分。

【讨论】:

  • 好主意。唯一的问题是 Objective-C 是 C 的严格超集,这意味着 ObjC 和 C 可以和平共存。这意味着我的大部分 C 函数都将具有__OBJC__#define'd。
【解决方案2】:

预处理器在解析实际代码之前完成所有工作。预处理器无法知道一个函数是 C 还是 obj-C,因为它在代码被解析之前运行。

出于同样的原因,

if (thisFunctionIsACFunction) {
  #define SELF nil
  #define CMD nil
} else {
  #define SELF self
  #define CMD _cmd
}
DoLogging(SELF, CMD, format, ##__VA_ARGS__);

不能工作 - #defines 在编译阶段之前处理。

因此,代码本身必须包含“运行时”检查(尽管编译器可能会对此进行优化)。

我建议定义类似的东西

void *self = nil; //not sure about the types that
SEL _cmd = nil;   //would be valid for obj-c

在全球范围内; C 函数将“看到”这些定义,而 Objective-C 方法有望用自己的定义隐藏它们。

【讨论】:

  • +1 哈!你真是个天才!我从来没有想过在全球范围内定义self_cmd!谢谢! (而且效果很好;我刚试过。)
【解决方案3】:

你可以使用

if defined "abc" <statement1>
else if defined "def" <statement2>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-01
    • 1970-01-01
    相关资源
    最近更新 更多