У меня всегда была привычка только к использованию станд.:: endl, потому что для меня легко видеть.
C не поддерживает такого рода операции (языки с отражением поддерживали бы). Лучшее, что вы сможете сделать, - это создать таблицу поиска от имен функций до указателей функций и использовать ее, чтобы выяснить, какую функцию вызывать. Или вы можете использовать оператор switch.
Хотя это не совсем практическое решение, держу пари, что вы, конечно, можете вызвать функцию с помощью строки, прочитав программу в ее собственном исполняемом файле и проанализируя таблицу символов. Таблица символов должна содержать имя функции, а также адрес ее первой инструкции. Затем вы можете поместить этот адрес в переменную указателя на функцию и вызвать ее.
Думаю, я могу попытаться это сделать.
РЕДАКТИРОВАТЬ: Пожалуйста, никто никогда не пишет настоящий код, подобный этому, но вот как вы можете вызвать функция, использующая строку для двоичного файла ELF Linux с неповрежденной таблицей символов (требуется libelf):
#include <fcntl.h>
#include <stdio.h>
#include <elf.h>
#include <libelf.h>
#include <stdlib.h>
#include <string.h>
void callMe() {
printf("callMe called\n");
}
int main(int argc, char **argv) {
Elf64_Shdr * shdr;
Elf64_Ehdr * ehdr;
Elf * elf;
Elf_Scn * scn;
Elf_Data * data;
int cnt;
void (*fp)() = NULL;
int fd = 0;
/* This is probably Linux specific - Read in our own executable*/
if ((fd = open("/proc/self/exe", O_RDONLY)) == -1)
exit(1);
elf_version(EV_CURRENT);
if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
fprintf(stderr, "file is not an ELF binary\n");
exit(1);
}
/* Let's get the elf sections */
if (((ehdr = elf64_getehdr(elf)) == NULL) ||
((scn = elf_getscn(elf, ehdr->e_shstrndx)) == NULL) ||
((data = elf_getdata(scn, NULL)) == NULL)) {
fprintf(stderr, "Failed to get SOMETHING\n");
exit(1);
}
/* Let's go through each elf section looking for the symbol table */
for (cnt = 1, scn = NULL; scn = elf_nextscn(elf, scn); cnt++) {
if ((shdr = elf64_getshdr(scn)) == NULL)
exit(1);
if (shdr->sh_type == SHT_SYMTAB) {
char *name;
char *strName;
data = 0;
if ((data = elf_getdata(scn, data)) == 0 || data->d_size == 0) {
fprintf(stderr, "No data in symbol table\n");
exit(1);
}
Elf64_Sym *esym = (Elf64_Sym*) data->d_buf;
Elf64_Sym *lastsym = (Elf64_Sym*) ((char*) data->d_buf + data->d_size);
/* Look through all symbols */
for (; esym < lastsym; esym++) {
if ((esym->st_value == 0) ||
(ELF64_ST_BIND(esym->st_info)== STB_WEAK) ||
(ELF64_ST_BIND(esym->st_info)== STB_NUM) ||
(ELF64_ST_TYPE(esym->st_info)!= STT_FUNC))
continue;
name = elf_strptr(elf,shdr->sh_link , (size_t)esym->st_name);
if(!name){
fprintf(stderr,"%sn",elf_errmsg(elf_errno()));
exit(-1);
}
/* This could obviously be a generic string */
if(strcmp("callMe", name) == 0 ) {
printf("Found callMe @ %x\n", esym->st_value);
fp = esym->st_value;
}
}
/* Call and hope we don't segfault!*/
fp();
elf_end(elf);
return 0;
}
Это невозможно в чистом C, однако вы можете сыграть шутки с dll. Поместите все функции, которые вы хотите выбрать, в dll, затем используйте dlsym
(или GetProcAddress
в Windows или любой другой API, который предлагает ваша система), чтобы получить указатель функции по имени, и вызовите его с помощью этого.
Это не работает на некоторых платформах либо потому, что у них вообще нет DLL, либо потому, что, как и в Symbian, к функциям в DLL нельзя получить доступ по имени во время выполнения, только по номеру .
Имейте в виду, что если ваш пользователь обманом заставит вас выбрать функцию, которая не имеет правильных параметров для вызова, который вы хотите сделать, ваша программа выйдет из строя.
Лучшее, что вы можете сделать, это что-то вроде этого:
#include <stdio.h>
// functions
void foo(int i);
void bar(int i);
// function type
typedef void (*FunctionCallback)(int);
FunctionCallback functions[] = {&foo, &bar};
int main(void)
{
// get function id
int i = 0;
scanf("%i", &i);
// check id
if( i >= sizeof(functions))
{
printf("Invalid function id: %i", i);
return 1;
}
// call function
functions[i](i);
return 0;
}
void foo(int i)
{
printf("In foo() with: %i", i);
}
void bar(int i)
{
printf("In bar() with: %i", i);
}
Здесь используются числа вместо строк для идентификации функций, но выполнение этого со строками - это просто вопрос преобразования строки в правильную функция
Что именно вы делаете? Если просто из любопытства, пожалуйста, но если вы пытаетесь решить проблему с этим, я уверен, что есть способ, лучше подходящий для вашей задачи.
Что касается вашего редактирования, вы наверняка захочет ответить onebyone .
Вы хотите, чтобы ваш пользователь создавал динамические библиотеки (это общий объект [.so] в Linux и библиотека динамической компоновки [.dll] в Windows).
После того, как вы это сделаете, если они предоставят вам имя своей библиотеки, вы можете попросить операционную систему загрузить эту библиотеку для вас,
Это то, что вы пытаетесь сделать:
void foo()
{
printf("foo called\n");
}
void bar()
{
printf("bar called\n");
}
int main()
{
char fun[10] = {'\0'};
printf("Enter function name (max 9 characters):");
scanf("%s",fun);
if(strcmpi(fun, "foo") == 0)
{
foo();
}
else if(strcmpi(fun, "bar") == 0)
{
bar();
}
else
{
printf("Function not found\n");
}
return 0;
}
#include <stdio.h>
#include <string.h>
void function_a(void) { printf("Function A\n"); }
void function_b(void) { printf("Function B\n"); }
void function_c(void) { printf("Function C\n"); }
void function_d(void) { printf("Function D\n"); }
void function_e(void) { printf("Function E\n"); }
const static struct {
const char *name;
void (*func)(void);
} function_map [] = {
{ "function_a", function_a },
{ "function_b", function_b },
{ "function_c", function_c },
{ "function_d", function_d },
{ "function_e", function_e },
};
int call_function(const char *name)
{
int i;
for (i = 0; i < (sizeof(function_map) / sizeof(function_map[0])); i++) {
if (!strcmp(function_map[i].name, name) && function_map[i].func) {
function_map[i].func();
return 0;
}
}
return -1;
}
int main()
{
call_function("function_a");
call_function("function_c");
call_function("function_e");
}
Как говорили другие, это правда, что C не имеет механизма отражения. Но вы можете добиться такого поведения, используя динамически загружаемую библиотеку / общий объект. Фактически, вы можете загрузить динамическую библиотеку, а затем вызывать функции в dll / so с их именем! Это не зависит от C и ОС, но это так. Он использует dlopen в Linux и LoadLibrary в Windows. Вы можете найти библиотеки, которые сделают эту работу за вас, например gtk / glib .
Если я правильно понял ваш вопрос, вы хотите использовать позднее связывание для вызова функции C. Это не то, что вы обычно можете делать в C. Символьные имена (например, имена функций) не сохраняются в коде, созданном компилятором C. Вы, вероятно, могли бы позволить компилятору испускать символы, а затем использовать их для выполнения позднего связывания, но методика будет варьироваться от компилятора к компилятору и, вероятно, не будет стоить хлопот.
Такие языки, как C # и Java, поддерживают отражение, что упрощает выполнить позднее связывание.
C arrays can only be indexed with integral types. So write a hash table mapping strings to function pointers.
It might also be worth looking at the facility in Python, Lua, other script languages to embed their run-time in a C program: parts of the C code can then be manipulated with the scripting language.
Alt'ly, some people code script language extensions in C. Then they can have the speed & low level access of C in their scripts.
You are going to find, sooner or later, that using dynamically typed script language idioms - like eval(), and the blurry line between function and function name, and code that depends on assoc arrays - in C is possible but ultimately painful.