Getting the name of a function, and the function that called it.

Pages: 12
May 22, 2010 at 11:59pm
I need to know this to help with debugging.

Sorry, the library is about to close so I don't have time to post more details, but I'll edit more details in tomorrow or monday when I have more time. In the meantime I'll post this to get you all started thinking...

something that I can put at the end of a problem function just before it returns that the end result will be something like:
cout << "end of f1() called from f2() " << endl;

Could I use function pointers too accomplish this? Of course I would have to pass another argument to each function, the function thats calling it.


Ideally, for any given problem code area, I want to be able to cout the immediate function, and ANY AND ALL functions that lead to the function in question being called.

Sorry I can't be more clear, I'll try to rethink my question in the meantime.
May 23, 2010 at 12:55am
No. Function names don't exist at run time. Some compilers might have some extension that lets you get the stack trace.
May 23, 2010 at 1:02am
I usually do it like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>
using namespace std;

class Debugger
{
    private:
    bool debug_mode;

    public:
    Debugger(){debug_mode=false;}

    void on(){debug_mode=true;}
    void off(){debug_mode=false;}

    Debugger & operator<<(const char * s)
    {if (debug_mode) cerr<<s; return *this;}

    Debugger & operator<<(char c)
    {if (debug_mode) cerr<<c; return *this;}

    Debugger & operator<<(int n)
    {if (debug_mode) cerr<<n; return *this;}

    Debugger & operator<<(long n)
    {if (debug_mode) cerr<<n; return *this;}

    Debugger & operator<<(double d)
    {if (debug_mode) cerr<<d; return *this;}
} debugger;

int add2(int a, int c);
int add3(int a, int b, int c);

int main()
{
    debugger.on(); //<-if you comment this out
                   //the debugger prints nothing...
    int a, b, c;

    cout << "enter 3 ints:\n";
    cin >> a >> b >> c;
    cin.get();

    cout << '\n' << a << '+' << b << '+' << c << '=';
    cout << add3(a,b,c) << endl;

    cout << "\nhit enter to quit...";
    cin.get();
    return 0;
}

int add2(int a, int b)
{
    debugger<<"\ninside add2("<<a<<','<<b<<")\n";

    int result;

    result=a+b;

    debugger<<"\nexiting add2...\nresult is:"<<result<<"\n";

    return result;
}

int add3(int a, int b, int c)
{
    debugger<<"\ninside add3("<<a<<','<<b<<','<<c<<")\n";

    int result;

    result=add2(a,b);
    result=add2(result,c);

    debugger<<"\nexiting add3...\nresult is:"<<result<<"\n";

    return result;
}
Last edited on May 23, 2010 at 1:05am
May 23, 2010 at 3:11am
And if you want something more sophisticated take a look at this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include <iostream>
#include <vector>
#include <string>
using namespace std;

class ArgumentList
{
    private:
    vector<void*> arg_list;

    public:
    ArgumentList & operator<<(void*arg)
    {arg_list.push_back(arg);return *this;}

    void * operator[](int i)
    {return arg_list[i];}

    void clear() {arg_list.clear();}
};

class Function
{
    public:
    string name;
    void * address;

    virtual void call(ArgumentList&,void*,Function*)=0;
    void operator()(ArgumentList&args,void*ret_val,Function*caller)
    {call(args,ret_val,caller);}
};

int add2(int a, int c);
int add3(int a, int b, int c);

class Fadd2:public Function
{
    public:
    Fadd2() {name="int add2(int,int)"; address=(void*)add2;}
    void call(ArgumentList&args,void * ret_val,Function*caller);

}fadd2;

class Fadd3:public Function
{
    public:
    Fadd3() {name="int add3(int,int,int)"; address=(void*)add3;}
    void call(ArgumentList&args,void * ret_val,Function*caller);

}fadd3;

int main()
{
    int a, b, c;

    cout << "enter 3 ints:\n";
    cin >> a >> b >> c;
    cin.get();

    cout << '\n' << a << '+' << b << '+' << c << '=';

    ArgumentList args;
    int result;

    args<<&a<<&b<<&c;
    fadd3(args,&result,0);

    cout << result << endl;

    cout << "\nhit enter to quit...";
    cin.get();
    return 0;
}

int add2(int a, int b)
{

    int result;

    result=a+b;

    return result;
}

int add3(int a, int b, int c)
{

    int result;
    ArgumentList args;

    args<<&a<<&b;

    fadd2(args,&result,&fadd3);

    args.clear();
    args<<&result<<&c;

    fadd2(args,&result,&fadd3);

    return result;
}

void Fadd2::call(ArgumentList&args,void * ret_val,Function*caller)
{
    //do ANYTHING you want in here...

    cout << '\n' << name << " called from " << (caller==0?"main":caller->name) << endl;

    static int times_called_from_add3=0;

    if(caller->address==add3) times_called_from_add3++;
    if(times_called_from_add3==2) cout << "\n(second time called from add3)" << endl;

    int * result=(int*)ret_val;
    int * arg1=(int*)args[0];
    int * arg2=(int*)args[1];

    *result=add2(*arg1,*arg2);

    cout << "\nreturning from " << name << endl;
}

void Fadd3::call(ArgumentList&args,void * ret_val,Function*caller)
{
    //same here...

    cout << '\n' << name << " called from " << (caller==0?"main":caller->name) << endl;

    int * result=(int*)ret_val;
    int * arg1=(int*)args[0];
    int * arg2=(int*)args[1];
    int * arg3=(int*)args[2];

    *result=add3(*arg1,*arg2,*arg3);

    cout << "\nreturning from " << name << endl;
}
Last edited on May 23, 2010 at 3:18am
May 23, 2010 at 10:31am
If you want to save the typing of the function name there is a preprocessor macro
 
__FUNC__


But it varies from compiler to compiler. This one is for MSVC.
May 23, 2010 at 10:33pm
m4ster r0shi, that looks something like I might find useful. how do I use it though? mind explaining me what each section of code does?

redx: what exactly does __FUNC__ do exactly?
May 23, 2010 at 11:08pm
that looks something like I might find useful. how do I use it though?

Did you see both my examples? Perhaps the first one is enough. There, I simply add some output lines inside every function. If you don't want this to mess with your program output you could output it to a file or something. This doesn't deserve more explanation.

In my second example I make a wrapper for every function in the program and use these wrappers to interact with my functions. This gives me more control over each function call. I know that there seems to be a problem with applying this to the constructors/destructors of your program classes but you can make all constructors/destructors do nothing, use different names for them and call them explicitly.

mind explaining me what each section of code does?

Um... It would be better if you told me what you don't understand...
May 24, 2010 at 2:33am
Nevermind the above, if what you only want is the names of the functions that have been called so far, it can be done like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <iostream>
#include <map>
#include <list>
#include <string>
using namespace std;

int main();
int add2(int a, int b);
int add3(int a, int b, int c);
int add5(int a, int b, int c, int d, int e);

map<void*,string> fnames;
list<void*> flist;

void init_fnames()
{
    fnames[(void*)main]="main";
    fnames[(void*)add2]="add2";
    fnames[(void*)add3]="add3";
    fnames[(void*)add5]="add5";
}

void view_flist()
{
    list<void*>::iterator it;

    for (it=flist.begin(); it!=flist.end(); it++)
    {
        cerr << fnames[*it] << '\n';
    }
}

int main()
{
    flist.push_back((void*)main);

    init_fnames();

    int a, b, c;

    cout << "enter 3 ints:\n";
    cin >> a >> b >> c;
    cin.get();

    cout << '\n' << a << '+' << b << '+' << c << '=';
    cout << add3(a,b,c) << endl;

    int d,e;
    cout << "enter 2 more ints:\n";
    cin >> d >>e;
    cin.get();

    cout << add5(a,b,c,d,e);

    cout << "\nhit enter to quit...";
    cin.get();

    flist.pop_back();

    return 0;
}

int add2(int a, int b)
{
    cout << "\ntracing function calls inside add2...\n";
    view_flist();

    flist.push_back((void*)add2);

    int result;

    result=a+b;

    flist.pop_back();

    return result;
}

int add3(int a, int b, int c)
{
    cout << "\ntracing function calls inside add3...\n";
    view_flist();

    flist.push_back((void*)add3);

    int result;

    result=add2(a,b);
    result=add2(result,c);

    flist.pop_back();

    return result;
}

int add5(int a, int b, int c, int d, int e)
{
    cout << "\ntracing function calls inside add5...\n";
    view_flist();

    flist.push_back((void*)add5);

    int result;

    result=add2(a,b);
    result=add2(result,add3(c,d,e));

    flist.pop_back();

    return result;
}

And for every new function you write for your program what you only need to do is add a line to the init_fnames() function and a couple of lines inside your new function.
Last edited on May 24, 2010 at 2:34am
May 24, 2010 at 3:19am
Interesting idea, master roshi.

Though a much simpler way, IMO, would be to just put a const char* in a list, instead of the whole weird cast-to-void-pointer and then lookup the string approach:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
list<const char*> flist;

//...

void view_flist()
{
    list<const char*>::iterator it;

    for (it=flist.begin(); it!=flist.end(); it++)
    {
        cerr << *it << '\n';
    }
}

//...

int afunction()
{
   flist.push_back("afunction");
   //...
}


the void pointers are pretty much useless since you can't cast back to the function without knowing what type the function was.
May 24, 2010 at 3:30am
Linked list of pointers? Just create a vector, reserve 5000 elements, and be done with it.
May 24, 2010 at 3:37am
That's a lot of memory, helios.

-Albatross
May 24, 2010 at 3:38am
20-40 thousand bytes is a lot of memory? The same structure as a doubly linked list reaches that mark at most at 1666 elements (not counting allocation overhead).
Last edited on May 24, 2010 at 3:41am
May 24, 2010 at 3:43am
Eh, sorry. Never mind what I said.

And... vectors are the better solution here.

-Albatross
Last edited on May 24, 2010 at 3:48am
May 24, 2010 at 3:51am
@wtf

I often use this technique:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#define bug(msg) std::cout << msg << std::endl

struct __func_scope
{
	std::string s;
	__func_scope(const std::string& s) : s(s){ bug("==> " << s); }
	~__func_scope() { bug("<== " << s); }
};

#define bug_func(msg) __func_scope __fs(__func__)


int func1()
{
	bug_func();

	// ... some code
}

void func2()
{
	bug_func();

	//... more code
}


It will display the entry and exit point of each function in which you place bug_func();
May 25, 2010 at 8:21am
helios wrote:
Linked list of pointers? Just create a vector, reserve 5000 elements, and be done with it.
helios wrote:
20-40 thousand bytes is a lot of memory? The same structure as a doubly linked list reaches that mark at most at 1666 elements (not counting allocation overhead).

No.

What if I have to resize? I understand that the chance is too small but there still is a chance... Suppose you're a hired assassin. You have two job offers, one with a reward of 1'666'666 $ but not risky at all, and one with a reward of 5'000'000 $ but with a 1% chance to die. Which one would you take? Furthermore, if you were smart enough, you would see that you can actually make 4'166'666 $ from the first job. How? Make a struct containing an array of 10 pointers and then implement your pointer container as a list of such structs. The only thing you'll need to add is an int (not per element, just one int) to hold the position of the last inserted element in the array of the last entry of your list.

Albatross wrote:
That's a lot of memory, helios.
Albatross wrote:
Eh, sorry. Never mind what I said.

And... vectors are the better solution here.

Dude... Why do you allow yourself to be manipulated so easily?...

Disch wrote:
Interesting idea, master roshi.

Thank you! ^^

Disch wrote:
Though a much simpler way, IMO, would be to just put a const char* in a list, instead of the whole weird cast-to-void-pointer and then lookup the string approach

I won't disagree with that. I did what I did because I was thinking of adding more functionality later, I'll give an example of what I mean when I find the time...

Disch wrote:
the void pointers are pretty much useless since you can't cast back to the function without knowing what type the function was.

There are effective ways to cast a void pointer to a usable function pointer on run-time ;)
May 25, 2010 at 1:58pm
For crying out loud, what's wrong with

std::cout << __FUNCTION__ << std::endl;

or

std::cout << __PRETTY_FUNCTION__ << std::endl;

at the top of every function? (or whatever macro your compiler supports)

May 25, 2010 at 2:14pm
@jsmith,
Can it differ? For example, gcc uses "__func__". There should be a standard...
May 25, 2010 at 2:17pm
I have a little key mapping in vi to insert a debug line that uses __FILE__ and __LINE__... I'm not sure how portable that is, either. I use gcc.
May 25, 2010 at 2:53pm
May 25, 2010 at 3:41pm
__FILE__ and __LINE__ are portable

__FUNC__ varies from compiler to compiler.
Pages: 12