有条件的宏扩张

抬头:这是一个奇怪的问题。

我有一些非常有用的宏,我喜欢用来简化一些日志记录。 例如,我可以做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作为构建的一部分。