Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I find the name of the calling function?

Tags:

c++

debugging

I have been using PRETTY_FUNCTION to output the current function name, however I have reimplemented some functions and would like to find out which functions are calling them.

In C++ how can I get the function name of the calling routine?

like image 982
Phil Hannent Avatar asked Dec 09 '08 15:12

Phil Hannent


People also ask

How will you identify a calling function and a called function?

The calling function supplies the input (the actual arguments), which are then used by the called function to process the parameters because it has the definition, carry out the instructions, and return whatever that should be returned. The function that another function calls is known as the called function.

What is calling a function called?

A function call is an expression that passes control and arguments (if any) to a function and has the form: expression (expression-listopt) where expression is a function name or evaluates to a function address and expression-list is a list of expressions (separated by commas).

What is the name of calling function inside the same function?

Recursion is the process of repeating items in a self-similar way. In programming languages, if a program allows you to call a function inside the same function, then it is called a recursive call of the function.


1 Answers

Here is a solution you can often use. It has the advantage of requiring no changes to the actual function code (no adding calls to stackwalk functions, changing parameters to pass in function names, or linking to extra libraries.). To get it working, you simply need to use a bit of preprocessor magic:

Simple Example

// orignal function name was 'FunctionName' void FunctionNameReal(...) {   // Do Something }  #undef FunctionName #define FunctionName printf("Calling FunctionName from %s\n",__FUNCTION__);FunctionNameReal 

You must rename your function temporarily, but see the note below for more suggestions. This will result in a printf() statement at each point of calling the function. Obviously, you have to make some arrangements if you are calling a member function, or need to capture the return value (Like pass the function call and __FUNCTION__ to a custom function that returns the same type...), but the basic technique is the same. You might want to use __LINE__ and __FILE__ or some other preprocessor macros depending on which compiler you have. (This example is specifically for MS VC++, but probably works in others.)

Also, you might want to put something like this in your header surrounded by #ifdef guards to conditionally turn it on, which can handle renaming the actual function for you as well.

UPDATE [2012-06-21]

I got a request to expand my answer. As it turns out, my above example is a bit simplistic. Here are some fully compiling examples of handling this, using C++.

Full Source Example with a return value

Using a class with operator() makes this pretty straight forward. This first technique works for freestanding functions with and without return values. operator() just needs to reflect the same return as the function in question, and have matching arguments.

You can compile this with g++ -o test test.cpp for a non-reporting version and g++ -o test test.cpp -DREPORT for a version that displays the caller information.

#include <iostream>  int FunctionName(int one, int two) {   static int calls=0;   return (++calls+one)*two; }  #ifdef REPORT   // class to capture the caller and print it.     class Reporter   {     public:       Reporter(std::string Caller, std::string File, int Line)         : caller_(Caller)         , file_(File)         , line_(Line)       {}        int operator()(int one, int two)       {         std::cout           << "Reporter: FunctionName() is being called by "           << caller_ << "() in " << file_ << ":" << line_ << std::endl;         // can use the original name here, as it is still defined         return FunctionName(one,two);       }     private:       std::string   caller_;       std::string   file_;       int           line_;    };  // remove the symbol for the function, then define a new version that instead // creates a stack temporary instance of Reporter initialized with the caller #  undef FunctionName #  define FunctionName Reporter(__FUNCTION__,__FILE__,__LINE__) #endif   void Caller1() {   int val = FunctionName(7,9);  // <-- works for captured return value   std::cout << "Mystery Function got " << val << std::endl; }  void Caller2() {   // Works for inline as well.   std::cout << "Mystery Function got " << FunctionName(11,13) << std::endl; }  int main(int argc, char** argv) {   Caller1();   Caller2();   return 0; } 

Sample Output (Reporting)

Reporter: FunctionName() is being called by Caller1() in test.cpp:44 Mystery Function got 72 Reporter: FunctionName() is being called by Caller2() in test.cpp:51 Mystery Function got 169 

Basically, anywhere that FunctionName occurs, it replaces it with Reporter(__FUNCTION__,__FILE__,__LINE__), the net effect of which is the preprocessor writing some object instancing with an immediate call to the operator() function. You can view the result (in gcc) of the preprocessor substitutions with g++ -E -DREPORT test.cpp. Caller2() becomes this:

void Caller2() {   std::cout << "Mystery Function got " << Reporter(__FUNCTION__,"test.cpp",51)(11,13) << std::endl; } 

You can see that __LINE__ and __FILE__ have been substituted. (I'm not sure why __FUNCTION__ still shows in the output to be honest, but the compiled version reports the right function, so it probably has something to do with multi-pass preprocessing or a gcc bug.)

Full Source Example with a Class Member Function

This is a bit more complicated, but very similar to the previous example. Instead of just replacing the call to the function, we are also replacing the class.

Like the above example, you can compile this with g++ -o test test.cpp for a non-reporting version and g++ -o test test.cpp -DREPORT for a version that displays the caller information.

#include <iostream>  class ClassName {   public:     explicit ClassName(int Member)       : member_(Member)       {}      int FunctionName(int one, int two)     {       return (++member_+one)*two;     }    private:     int member_; };  #ifdef REPORT   // class to capture the caller and print it.     class ClassNameDecorator   {     public:       ClassNameDecorator( int Member)         : className_(Member)       {}        ClassNameDecorator& FunctionName(std::string Caller, std::string File, int Line)       {         std::cout           << "Reporter: ClassName::FunctionName() is being called by "           << Caller << "() in " << File << ":" << Line << std::endl;         return *this;       }       int operator()(int one, int two)       {         return className_.FunctionName(one,two);       }     private:       ClassName className_;   };   // remove the symbol for the function, then define a new version that instead // creates a stack temporary instance of ClassNameDecorator. // FunctionName is then replaced with a version that takes the caller information // and uses Method Chaining to allow operator() to be invoked with the original // parameters. #  undef ClassName #  define ClassName ClassNameDecorator #  undef FunctionName #  define FunctionName FunctionName(__FUNCTION__,__FILE__,__LINE__) #endif   void Caller1() {   ClassName foo(21);   int val = foo.FunctionName(7,9);  // <-- works for captured return value   std::cout << "Mystery Function got " << val << std::endl; }  void Caller2() {   ClassName foo(42);   // Works for inline as well.   std::cout << "Mystery Function got " << foo.FunctionName(11,13) << std::endl; }  int main(int argc, char** argv) {   Caller1();   Caller2();   return 0; } 

Here is sample output:

Reporter: ClassName::FunctionName() is being called by Caller1() in test.cpp:56 Mystery Function got 261 Reporter: ClassName::FunctionName() is being called by Caller2() in test.cpp:64 Mystery Function got 702 

The high points of this version are a class that decorates the original class, and a replacement function that returns a reference to the class instance, allowing the operator() to do the actual function call.

like image 181
Aaron Avatar answered Sep 21 '22 16:09

Aaron