【问题标题】:Using macro in Objective-C to log function name and line number在 Objective-C 中使用宏来记录函数名和行号
【发布时间】:2011-05-29 06:10:45
【问题描述】:

我有以下简化代码示例:

// in .h file
// define a macro for partial method
#define debugWithMsg context:(CFStringRef)__FUNCTION__ lineNumber:__LINE__ debug:

@interface MyLogger : NSObject {
  ...
}

- (void) context:(CFStringRef)function 
      lineNumber:(int)line 
           debug:(NSString*)messageFormat, ...;
@end

我在其他类中使用此方法将调试消息打印到 XCode 控制台。这是我测试调试方法的示例(在带有表视图的 MyViewController 类中):

- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section {
  ...
  // myLogger is an instance of MyLogger.
  [myLogger debugWithMsg@"something for %@", @"testing!"];
  ...
}
...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  ...
  [myLogger debugWithMsg@"something for %@", @"another testing!"];
  ...
}

上面的例子效果很好;但是,对我来说,它看起来不像标准的 C/C++ 或 ObjC 语法。我需要使用这个宏的原因是我想将前两个参数作为“常量”传递给方法。实际上,这两个参数也是宏:__FUNCTION__ 是 C++ 宏,而 __LINE__ 是 C 标准宏。这两个特殊宏将动态映射到函数字符串和调用方法的行号。例如,上面的调试方法调用会在 XCode 控制台中打印一条消息,如下所示:

[timestamp] -[MyViewController tableView:numberOfRowsInSection:] line:107 - something for testing!
...
[timestamp] -[MyViewController tableView:cellForRowAtIndexPath:] line:124 - something for another testing!

MyLogger 类主要供我内部使用。有没有其他更好的做法来获得相同的结果?或者这个实现有什么问题吗?

我正在考虑以与 NSLog(fmt, ...) 相同的方式定义我的宏,这也是一个宏:

MyDebugLog(instance, fmt, ....)

instance 是 MyLogger 的一个实例,fmt, ... 是格式字符串和 var 列表。这是我对宏的试用定义:

#define MyDebugLog(logger, fmt, ...) \
  [logger, context:(CFStringRef)__FUNCTION__ lineNumber:__LINE__ \
   debug:fmt, ## _VA_ARGS__]

我在使用宏的代码中出现编译错误“'context' undeclared”:

- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section {
  ...
  // myLogger is an instance of MyLogger.
  MyDebugLog(myLogger, @"something for %@", @"testing!"); // compiling error!
  ...
}

不确定我的定义有什么问题。有什么建议?

【问题讨论】:

  • 请注意,__LINE__ 扩展为数字,而不是字符串。
  • 您更新后的#define 不应在[logger context: 中包含,
  • @Stephen,很好,你是对的!谢谢!
  • 很高兴我能帮上忙。希望它对你有用。

标签: c++ objective-c c


【解决方案1】:

这是我用的。

#define SFLog(message, ...) NSLog((@"SFLOG: %s [Line %d] " message), __PRETTY_FUNCTION__, __LINE__, ## __VA_ARGS__)

您可以像使用 SFLog(@"Some var %f", myFloat); 一样使用它,只是它预先添加了“SFLog”(我也使用“SFError”)和 __PRETTY_FUNCTION__ 宏。


[编辑]

我找到了我得到这个的 SO 帖子。 It's over here.


[编辑]

评论者Jonathan Leffler 在下面指出,可以在没有## 的情况下定义宏。 ## 纯粹是 GCC 的东西,不符合 C99 标准。 ## 也适用于 LLVM/Clang 1.5 (XCode 3.2.4) 以及 -std=c99 和 -std=gnu99 的编译器设置。请理解,如果宏不能按预期工作,它会有一些限制。

【讨论】:

  • @Jonathan,两个哈希值对我有用。你可能只需要一个,我承认我知道的不够多,无法告诉你区别。
  • 奇怪......它“不应该”工作;单个哈希是字符串化运算符;双散列是令牌粘贴运算符。实际上,仔细想想,双重哈希根本不应该存在,但这并不能解释为什么它被允许。
  • @Jonathan,根据我得到它的 SO 帖子,## 可以防止参数的宏扩展。
  • 刚刚检查过 - 它可以双向工作(例如,GCC 的 C 预处理器不会抱怨。对于简单的情况,产生相同的结果。让我玩一下宏......
  • @Jonathan,有趣的是,同样的问题也发给了宏的原作者。这可能是一个编译器技巧/黑客,这就是它不常见的原因。
猜你喜欢
  • 2011-05-31
  • 1970-01-01
  • 2011-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-07
  • 1970-01-01
相关资源
最近更新 更多