2016-06-30 3 views
0

В следующем коде get_func_name() может быть системным вызовом, вызовом библиотеки или функцией, определенной мной самим. Без принятия каких-либо параметров, как я могу позволить get_func_name() распечатать имя вызывающей функции, не используя информацию из стека?Как распечатать имя вызывающей функции, не глядя на стек?

Кроме того, помимо имени вызывающего, могу ли я распечатать что-либо в get_func_name(), которое может однозначно идентифицировать вызывающего абонента?

void get_func_name(){ 
     /*What magic goes here?*/ 
} 

void func2(){ 
     func3(); 
     get_func_name(); /*Should print out "func2()"*/ 
} 

void func1(){ 
     func2(); 
     get_func_name(); /*Should print out "func1()"*/ 
} 

void main(){ 
     func1(); 
     get_func_name(); /*Should print out "main()"*/ 
} 
+0

Можете ли вы передать имя вызывающей функции в функцию 'get_func_name()'? Вы говорите «нет» ... тогда я не думаю, что вам есть возможность узнать вызывающую функцию, не проверяя фреймы стека (содержимое стека), чтобы узнать вызывающую функцию, и даже это очень сложно, особенно если функции встраиваемый. –

+0

Не без проверки стека. Вам нужно будет найти обратный адрес в стеке. Это идентифицирует вызывающую функцию благодаря знанию диапазона адресов для каждой функции, что означает просмотр эзотерической, высокоплатформенной информации (которая может даже не присутствовать). Есть библиотеки, которые делают это, но они проверяют стек. Один (плохой) способ сделать это - иметь преамбулу и postamble для каждой функции, которая подталкивает свое имя ('__func__') к стеку указателей (контролируемых пользователем); то вы можете найти вызывающую иерархию. Боль заключается в том, что никто не ошибается. –

+0

@ Джонатан. Даже проверка стека не помогла бы; Нет никакой гарантии, что строка, содержащая имя вызывающей функции, существует даже в двоичном (например, статические функции, которые не образуют внешний интерфейс и имя которых, таким образом, не должно записываться как точка входа). Эти же функции могут быть встроены в собственные вызовы, поэтому обратный адрес будет указывать на вызывающего абонента. Наконец, если вызывающий абонент является частью цепочки вызовов, обратный указатель указывает на функцию, которая инициировала цепочку; Это может быть * очень * далеким от непосредственной функции вызова. –

ответ

2

Это зависит от вашего сценария.

Вы можете рассмотреть предопределенный идентификатор __func__. Стандарт говорит:

Идентификатор __func__ должен быть неявно объявляется переводчиком, как если бы, сразу после открытия скобки каждого определения функции, заявление

static const char __func__[] = "function-name"; 

появился, где имя-функции является имя лексически-охватывающей функции.
....

Пример Рассмотрим фрагмент кода:

#include <stdio.h> 
void myfunc(void) 
{ 
    printf("%s\n", __func__); 
    /* ... */ 
} 

Каждый раз, когда вызывается функция, она будет печатать на стандартный поток вывода:

myfunc 

Вы можете несколько имитировать get_func_name с таким макросом:

#define print_func_name() { printf("%s\n", __func__); } 

Однако, если ваша задача отличается, и вы хотите, чтобы имя вызывающего в общем случае, я не вижу способа получить ее, не проверяя стек. (И даже если у вас есть доступ к стеку, вам нужно отладочную информацию, чтобы сопоставить адрес вызывающего абонента с именем вызывающего абонента.)

+0

Спасибо @AlexD.Является ли макрос \ _ \ _ func \ _ \ _ получить имя функции из стека? –

+2

Нет, это не так: переменная '__func__' статична и поэтому живет в секвенте данных. – Purag

+0

@QiZhang: предопределенный идентификатор '__func__' содержит имя текущей функции. Если вы использовали '__func__' в' get_func_name() ', он сообщал бы' get_func_name' и не сообщал бы имя вызывающей функции. В результате я не думаю, что этот ответ помогает решить проблему. –

Смежные вопросы