有条件的宏扩张
抬头:这是一个奇怪的问题。
我有一些非常有用的宏,我喜欢用来简化一些日志记录。 例如,我可以做Log(@"My message with arguments: %@, %@, %@", @"arg1", @"arg2", @"arg3")
,这将扩展为更复杂的方法调用包括self
, _cmd
, __FILE__
_cmd
__FILE__
, _cmd
等等,以便我可以轻松跟踪记录事件的位置。 这很好用。
现在我想扩展我的宏,不仅可以使用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
以一种非常基本的方式确定(我肯定对改进和建议thisFunctionIsACFunction
开放态度)。 基本上是这样的:
BOOL thisFunctionIsACFunction == (__PRETTY_FUNCTION__[0] != '-' && __PRETTY_FUNCTION__[0] != '+');
它依赖于编译器的行为,为Objective-C对象的实例和类方法添加’ – ‘或’+’。 其他任何东西都必须是C函数(因为C函数的名称不能以’ – ‘或’+’开头)。
我理解这个检查在技术上是一个运行时检查,因为__PRETTY_FUNCTION__
被char*
替换,这可能是我请求帮助的主要障碍。
预处理器在解析实际代码之前完成所有工作。 预处理器无法知道函数是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方法将希望用自己的定义隐藏它们。
您可以使用
if defined "abc" else if defined "def"
您可以使用某种宏条件:
#ifndef OBJECTIVE_C #define self 0 #define _cmd "" #endif
我不太清楚你应该定义什么样的self
和_cmd
,这些只是猜测。
我不确定是否有预定义的宏可以检查您是否在Objective C中进行编译,因此您可能需要手动定义OBJECTIVE_C
作为构建的一部分。