Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ function call identifier

Consider the following code:

void Foo() {
  ......
  LOG_ERROR("I'm error 1")   // call 1
  .....
  LOG_ERROR("I'm error 2")  // call 2
  .....

}

LOG_ERROR() is a macro. LOG_ERROR() should print string identifying it in code, while the assumption is that code can change, but A::Foo() will remain unchanged. The identifier should retain while code changes.

This can be solved by adding error code as argument to LOG_ERROR(), but we want to remove from the programmer the burden to manage error codes.

Using __LINE__ is not an answer, since Foo() can move from build to build.

Therefore I thought about identifying LOG_ERROR() relative to start of Foo():

  • a. Identify by file name (__FILE__) + function name (__FUNCTION__) + line number of LOG_ERROR() relative to Foo() start.
  • b. Identify by file name (__FILE__) + function name (__FUNCTION__) + LOG_ERROR() call number in Foo().

The solution should be work with VC++ 2008 and g++ 4.1.1 at least.

One proposed solution (link text) is:

#define ENABLE_LOG_ERROR static const int LOG_ERROR_start_line = __LINE__
#define LOG_ERROR(s) cerr << "error #" << (__LINE__ - LOG_ERROR_start_line) \
    << " in " << __func__ << ": " << s << endl

void Foo() {
     ENABLE_LOG_ERROR;
     //...
     LOG_ERROR("error 1");
     int i;
     LOG_ERROR("error 2");
} 

This will force user to write ENABLE_LOG_ERROR in start of each function containing LOG_ERROR() and there're many such functions.

Is there other way to accomplish the task?

like image 650
dimba Avatar asked Nov 05 '22 20:11

dimba


2 Answers

This solution is non-standard, but both MSVC and GCC support __COUNTER__, which is incremented every time it is invoked.

#define LOG_ERROR(s) cerr << "error #" << (__COUNTER__) << " in " \
<< __func__ << ": " << s << endl

Note that __COUNTER__ will be reset in each compilation unit, and ONLY in each compilation unit. So if Foo() has 7 LOG_ERROR() macros, in a later function Bar() the value of __COUNTER__ will be 7 for the first use of LOG_ERROR().

like image 85
Geerad Avatar answered Nov 12 '22 22:11

Geerad


While the question is about ways to generate unique line identifiers within a function for logging purposes, I'm going to take a step back and look at the actual problem to be solved: How to generate log output which can easily identify the source code line without putting the burden on the writer of the code.

Let's assume you are embedding a unique build version in each release of your program (which is a good idea in general). Let's also assume you are using a source code control mechanism which keeps the history of your source code (which is also a very good idea to be doing anyway) and which can present you with the source as it was for any requested build version of the program.

If those assumptions hold true, then a solution is to have your program write it's current version into the log file. Then each individual logging entry can simply record the line number via __LINE__.

Thus, when someone needs to use the log: they can look at the version number in the log, grab the corresponding source from the source code control repository, and use the line numbers from the log to go to the proper source lines. This puts a bit more burden on the person using the log output. However, if logged code depends on or is influenced by other code which could change from version to version, then the historical state of the source code might be required anyway.

Furthermore, a benefit of working this way is that it removes to need to assume that any given function will remain unchanged, as was originally part of the question. So this method has a much broader application.


As far as implementation goes, you could either log the program version when the program starts up or you could make the logging macro include it in each entry.

If the program version is normally stored somewhere not easily accessible in normal source code, then you could create a pre-build step which would extract the version and write it into a simple version.h file as a #define or const string. Then the logging code or macro could automatically use that to always output the current version of the program.

like image 40
TheUndeadFish Avatar answered Nov 12 '22 21:11

TheUndeadFish