Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
895 views
in Technique[技术] by (71.8m points)

c++ - Using macro in Objective-C to log function name and line number

I have the following simplified code example:

// 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

I use this method in other classes to print debug messages to XCode console. Here is an example I test my debug method(in MyViewController class with a table view):

- (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!"];
  ...
}

The above example works well; however, for me, it does not look like a standard C/C++ or ObjC syntax. The reason I need to use this macro is that I would like to pass the first two arguments as "constants" to the method. Actually, those two arguments are also macros: __FUNCTION__ being a C++ macro, and __LINE__ being a C standard macro. Those two special macros would be dynamically mapped to a string of the function and a line number where the method is called. For example the above debug method call prints a msg in XCode console like this:

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

The MyLogger class is mainly for my internal use. Is there any other better practice to get the same result? Or is there any problem with this implementation?

I am thinking to define my macro in the same way as NSLog(fmt, ...), which is a macro as well:

MyDebugLog(instance, fmt, ....)

where instance is an instance of MyLogger, and fmt, ... are format string and var list. This is my trial definition of the macro:

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

I got compiling error saying "'context' undeclared" in my code where the macro is used:

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

Not sure what's wrong in my definition. Any suggestions?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This is what I use.

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

You use it exactly like SFLog(@"Some var %f", myFloat); except it prepends the 'SFLog' (I also use 'SFError') and the __PRETTY_FUNCTION__ macros.


[EDIT]

I found the SO post where I got this. It's over here.


[Edit]

Commenter Jonathan Leffler points out below that the macro can be defined without the ##. The ## is purely a GCC thing, and doesn't conform to C99 standard. ## also works with LLVM/Clang 1.5 (XCode 3.2.4) as well as compiler settings for -std=c99 and -std=gnu99. Just understand that there are some limitations for the macro if it doesn't work as expected.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...