Получить указатель на текущую функцию в C (gcc)?
Есть ли волшебная переменная в gcc, удерживающая указатель на текущую функцию?
Я хотел бы иметь какую-то таблицу, содержащую для каждого указателя функции набор информации.
Я знаю там переменную __func__, содержащую имя текущей функции в виде строки, но не как указатель функции.
Это не вызов функции, а только для использования в качестве индекса.
ИЗМЕНИТЬ
В основном то, что я хотел бы сделать, это возможность запуска вложенных функций непосредственно перед выполнением текущей функции (а также захват возврата для выполнения некоторых действий).
В принципе, это похоже на __cyg_profile_func_enter и __cyg_profile_func_exit (функции инструментария)... Но проблема в том, что эти инструментальные функции являются глобальными, а не функциями.
ИЗМЕНИТЬ
В ядре linux вы можете использовать unsigned long kallsyms_lookup_name(const char *name)
от include/linux/kallsyms.h
... Обратите внимание, что параметр CONFIG_KALLSYMS
должен быть активирован.
Ответы
Ответ 1
Вот трюк, который получает адрес вызывающего абонента, его, вероятно, можно немного почистить.
Опирается на расширение GCC для получения значения метки.
#include <stdio.h>
#define MKLABEL2(x) label ## x
#define MKLABEL(x) MKLABEL2(x)
#define CALLFOO do { MKLABEL(__LINE__): foo(&&MKLABEL(__LINE__));} while(0)
void foo(void *addr)
{
printf("Caller address %p\n", addr);
}
int main(int argc, char **argv)
{
CALLFOO;
return 0;
}
Ответ 2
void f() {
void (*fpointer)() = &f;
}
Ответ 3
#define FUNC_ADDR (dlsym(dlopen(NULL, RTLD_NOW), __func__))
И скомпилируйте свою программу, например
gcc -rdynamic -o foo foo.c -ldl
Ответ 4
Если вы отправились на С++, следующая информация может вам помочь:
Набираются объекты, functors - это функции, завернутые как объекты, RTTI позволяет идентифицировать тип во время выполнения.
Функторы несут накладные расходы во время выполнения, и если это будет проблемой для вас, я бы предложил жесткое кодирование знаний с использованием генерации кода или использования OO-иерархии функторов.
Ответ 5
Я думаю, вы могли бы построить свою таблицу, используя строки (имена функций) в качестве ключей, а затем посмотреть, сравнив их с встроенной переменной __func__
.
Чтобы обеспечить наличие допустимого имени функции, вы можете использовать макрос, который получает указатель на функцию, выполняет с ним некоторую фиктивную операцию (например, назначая его временной переменной совместимого типа), чтобы проверить, действительно ли это действительный идентификатор функции, а затем строит (С#) имя функции перед использованием в качестве ключа.
UPDATE:
Я имею в виду что-то вроде:
typedef struct {
char[MAX_FUNC_NAME_LENGTH] func_name;
//rest of the info here
} func_info;
func_info table[N_FUNCS];
#define CHECK_AND_GET_FUNC_NAME(f) ({void (*tmp)(int); tmp = f; #f})
void fill_it()
{
int i = -1;
strcpy(table[++i].func_name, CHECK_AND_GET_FUNC_NAME(foo));
strcpy(table[++i].func_name, CHECK_AND_GET_FUNC_NAME(bar));
//fill the rest
}
void lookup(char *name) {
int i = -1;
while(strcmp(name, table[++i]));
//now i points to your entry, do whatever you need
}
void foo(int arg) {
lookup(__func__);
//do something
}
void bar(int arg) {
lookup(__func__);
//do something
}
(для кода могут потребоваться некоторые исправления, я не пытался его скомпилировать, это просто для иллюстрации идеи)
Ответ 6
Нет, функция не знает о себе. Вам нужно будет построить таблицу, о которой вы говорите о себе, а затем, если вы хотите, чтобы функция знала о себе, вам нужно будет передать индекс в глобальную таблицу (или указатель функции) в качестве параметра.
Примечание. Если вы хотите сделать это, вы должны иметь согласованную схему именования параметра.
Ответ 7
Если вы хотите сделать это "общим" способом, тогда вы должны использовать средства, о которых вы уже упоминали (__cyg_profile_func*
), так как это то, для чего они предназначены. Все остальное должно быть как ad hoc в качестве вашего профиля.
Честно говоря, делая общий путь (с фильтром), вероятно, меньше подвержен ошибкам, чем любой новый метод, который вы будете вставлять "на лету".
Ответ 8
Вы можете записать эту информацию с помощью setjmp()
. Поскольку он сохраняет достаточно информации для возврата к вашей текущей функции, он должен включать эту информацию в предоставленный jmp_buf
.
Эта структура очень не переносима, но вы указываете GCC явно, чтобы, вероятно, не проблема блокировки. См. этот пример GCC/x86, чтобы понять, как это работает.
Ответ 9
Если вы хотите создать код, я бы рекомендовал GSLGen из Imatix. Он использует XML для структурирования модели вашего кода, а затем простой PHP, такой как язык нисходящего поколения, который выплевывает код - он использовался для генерации кода C.
Я лично играл с lua для создания кода.
Ответ 10
static const char * const cookie = __FUNCTION__;
__FUNCTION__
будет сохранен в текстовом сегменте в вашем двоичном файле, и указатель всегда будет уникальным и действительным.
Ответ 11
Другой вариант, если переносимость не является проблемой, - это настроить исходный код GCC... любых добровольцев?!
Ответ 12
Если вам нужно только уникальный идентификатор для каждой функции, то в начале каждой функции поместите это:
static const void * const cookie = &cookie;
Тогда значение cookie
гарантируется как значение, однозначно идентифицирующее эту функцию.