In this article I will discuss a neat trick that allows to find out where a function was called from at run time. It demonstrates an interesting use of macros, both self-written and environment-defined. The method is 100% standard C++, and should work on every compliant compiler. I want to do something like:

void foo(void)
{
    // ...
    // ...

    std::cout << "Hey there !\n";
    std::cout << "I was called from " << ???;

    // ...
}
If the function is called from only one place in your program, it's hardly an issue. But what if it's a library function, called hundreds of times, from many places throughout the code ? "What is the big problem", you may think. When we're executing a function, can't we just look at the stack and see where we were called from (after all, the return address is stored there) ? Well, no, it's not a good method. Why ? First, it isn't very easy to do, even if you find out the return address, how do you know, at run time, where this address refers to ? Second and more important, this is not portable. Even if you think of some clever hack to solve the problem on one platform, it most likely won't work on another. Memory addresses and stacks are highly platform specific. The method I propose is very simple and absolutely portable. One interesting aspect of it is that it uses macros. While #define is "the way" to go when constants and macros are needed in C, seasoned C++ programmers prefer not to use them at all, using const and inline instead. #define is only left for "legacy code" and "special cases". I believe that the trick I will demonstrate is an examply of such a "special case". #define statements have a unique property: they are translated at compile time. This property can be used to invisibly embed location info into a function call. Consider the code:

#include 

using namespace std;

// Macro substitution
//
#define foo(a) foo_aux(a, __FILE__, __LINE__)

// Forward declaration
void foo_aux(int a, char* file, int line);

int main()
{
    // Call foo(6), but actually foo_aux(6, 
    // [line number], [file name]) when the 
    // line number and file name are inserted 
    // by the compiler
    //
    foo(6);
    return 0;
}

// Same function as "foo", just changed
// the name
//
void foo_aux(int a, char* file, int line)
{
    
    // ...
    // ...  
    cout << "Hey there !\n";
    cout << "I was called from line " 
           << line << " in file " << file;

   // ...
}
Note: No changes are needed in the program code, except some hacking around the function foo. Its name is changed to foo_aux and a macro named foo is created. This macro passes two implicit parameters (meaning that the caller knows nothing about them) to foo_aux which uses them to find out exactly where it was called from using the known __LINE__ and __FILE__ macros. These two are part of the C++ standard. Whenever the compilers sees them, it replaces them with the line number in file and source file name. So, for example, if foo is called on line 25 of file test.cpp, the call: foo(6); is translated to: foo_aux(6, "test.cpp", 25); The best part is that the change can be applied to a large chunk of code by changing only a couple of lines of code ! Just change the function name (both in declaration and definition) and add a macro with a name similar to the old function name, with the extra parameters. Voila ! No need to change the calls to your function all throughout the code, they will be translated automatically. It is not hard to imagine a situation when this trick can be useful. For example, through a debugging phase of a project, if you see that some function receives illegal parameters, you can use this method to verify where it's getting them from, etc. If you apply it to an interesting situation or it helps you solve a problem, I'll be glad to hear about it, so drop me a note. Enjoy !

Comments

comments powered by Disqus