Определяет, какая функция указатель указывает на C?
У меня есть указатель на функцию, предполагаю любую подпись.
И у меня есть 5 различных функций с одинаковой подписью.
Во время выполнения один из них назначается указателю, и эта функция вызывается.
Не вставляя какой-либо оператор печати в эти функции, как я могу узнать имя функции, на которую указывает указатель?
Ответы
Ответ 1
Вам нужно будет проверить, какие из 5 функций указывают ваш указатель:
if (func_ptr == my_function1) {
puts("func_ptr points to my_function1");
} else if (func_ptr == my_function2) {
puts("func_ptr points to my_function2");
} else if (func_ptr == my_function3) {
puts("func_ptr points to my_function3");
} ...
Если это общий шаблон, который вам нужен, используйте таблицу структур вместо указателя функции:
typedef void (*my_func)(int);
struct Function {
my_func func;
const char *func_name;
};
#define FUNC_ENTRY(function) {function, #function}
const Function func_table[] = {
FUNC_ENTRY(function1),
FUNC_ENTRY(function2),
FUNC_ENTRY(function3),
FUNC_ENTRY(function4),
FUNC_ENTRY(function5)
}
struct Function *func = &func_table[3]; //instead of func_ptr = function4;
printf("Calling function %s\n", func->func_name);
func ->func(44); //instead of func_ptr(44);
Ответ 2
Как правило, в C такие вещи недоступны программисту.
Могут существовать системные способы доступа туда, используя символы отладки и т.д., но вы, вероятно, не хотите зависеть от их наличия для нормальной работы программы.
Но вы можете, конечно, сравнить значение указателя с другим значением, например.
if (ptr_to_function == some_function)
printf("Function pointer now points to some_function!\n");
Ответ 3
Имена функций не будут доступны во время выполнения.
C не является отражающим языком.
Либо сохранить таблицу указателей функций с помощью имени, либо предоставить режим вызова каждой функции, которая возвращает имя.
Ответ 4
Отладчик может сказать вам, что (например, имя функции, учитывая ее адрес).
Символьная таблица исполняемого файла ELF также может помочь. См. nm (1), objdump (1), readelf (1)
Другим подходом Linux GNU/libc может быть использование во время выполнения функции dladdr (3). Предполагая, что ваша программа красиво и динамически связана (например, с -rdynamic
), она может найти имя символа и путь к общему объекту с учетом некоторого адреса (функции, названной глобально).
Конечно, если у вас есть только пять функций данной подписи, вы можете сравнить свой адрес (с пятью адресами из них).
Обратите внимание, что некоторые функции не имеют ((глобально видимых) имен, например функций static
.
И некоторые функции могут быть dlopen
-ed и dlsym
-ed (например, внутри плагинов). Или их код синтезируется во время выполнения некоторой структурой JIT-ing (libjit
, gccjit
, LLVM
, asmjit
). И оптимизирующий компилятор может (и делает!) Встроенные функции, клонировать их, tail-call их и т.д., поэтому ваш вопрос может вообще не иметь никакого смысла...
См. также backtrace (3) и Ian Taylor libbacktrace внутри GCC.
Но в целом ваш квест невозможно. Если вам действительно нужна такая отражающая информация надежным способом, управляйте ею самостоятельно (посмотрите на систему Pitrat CAIA в качестве примера, или как-то мой MELT), возможно, генерируя некоторый код во время сборки.
Ответ 5
Чтобы узнать, где указывает указатель на функцию, вы должны будете отслеживать свою программу. Наиболее распространенным является объявление массива указателей на функции и использование переменной int в качестве индекса этого массива.
В настоящее время также можно сказать во время выполнения ту функцию, которая выполняется в данный момент, с помощью идентификатора __func__
:
#include <stdio.h>
typedef const char* func_t (void);
const char* foo (void)
{
// do foo stuff
return __func__;
}
const char* bar (void)
{
// do bar stuff
return __func__;
}
int main (void)
{
func_t* fptr;
fptr = foo;
printf("%s executed\n", fptr());
fptr = bar;
printf("%s executed\n", fptr());
return 0;
}
Вывод:
foo executed
bar executed
Ответ 6
Совсем нет - символическое имя функции исчезает после компиляции. В отличие от рефлексивного языка, C не знает, как его синтаксические элементы были названы программистом; особенно, нет никакого "поиска функции" по имени после компиляции.
Конечно, у вас может быть "база данных" (например, массив) указателей на функции, с помощью которой вы можете сравнить свой текущий указатель.
Ответ 7
Это совершенно ужасно и не переносимо, но при условии:
- Вы находитесь в Linux или какой-то подобной системе на базе ELF.
- Вы используете динамическую компоновку.
- Функция находится в общей библиотеке или вы использовали
-rdynamic
при связывании.
- Наверное, многие другие предположения, которые вы не должны делать...
Вы можете получить имя функции, передав ее адрес нестандартной dladdr
функции.
Ответ 8
- установите ваш компоновщик для вывода файла MAP.
- приостановить программу
- проверить адрес, содержащийся в указателе.
- найдите адрес в файле MAP, чтобы узнать, на какую функцию указывают.
Ответ 9
Указатель на функцию C - это адрес, как любой указатель. Вы можете получить значение из отладчика. Вы можете наложить указатель на любой целочисленный тип с достаточным количеством бит, чтобы выразить его полностью, и распечатать его. Любой блок компиляции, который может использовать указатель, т.е. Имеет имя функции в области видимости, может печатать значения указателя или сравнивать их с переменной времени выполнения, не затрагивая ничего внутри самих функций.