Подтвердить что ты не робот

Получить указатель на текущую функцию в 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 должен быть активирован.

4b9b3361

Ответ 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 гарантируется как значение, однозначно идентифицирующее эту функцию.