函数名作为C中main的参数

san*_*p22 6 c function-pointers

我有一个主要功能如下:

#include <stdio.h>

int main(int argc, char *argv[])
{
    int i, sum = 0;
    char *func_user = argv[1];

    // execute func_user function

    return 0;
}

void foo1(void)
{
    printf("I'm foo1.");
}

void foo2(void)
{
    printf("I'm foo2.");
}

void foo3(void)
{
    printf("I'm foo3.");
}
Run Code Online (Sandbox Code Playgroud)

我希望用户将他的函数名称作为main的参数,我希望我的程序执行这个给定的函数.有没有办法做这个(比如使用反射)而不使用switch/case方法?

Som*_*ude 14

你不能直接这样做,因为C既没有内省也没有反思.您必须自己名称(字符串)映射到(指向a)函数.

一种不常见的创建这种映射的方法是使用具有该信息的结构,然后对所有函数使用这些结构的数组.然后迭代数组以查找名称及其函数指针.

也许是这样的

struct name_function_map_struct
{
    char *name;             // Name of the function
    void (*function)(void); // Pointer to the function
};

// Declare function prototypes
void foo1(void);
void foo2(void);
void foo3(void);

// Array mapping names to functions
const struct name_function_map_struct name_function_map[] = {
    { "foo1", &foo1 },
    { "foo2", &foo2 },
    { "foo3", &foo3 }
};

int main(int argc, char *argv[])
{
    // Some error checking
    if (argc < 2)
    {
        // Missing argument
        return 1;
    }

    // Calculate the number of elements in the array
    const size_t number_functions = sizeof name_function_map / sizeof name_function_map[0]

    // Find the function pointer
    for (size_t i = 0; i < number_functions; ++i)
    {
        if (strcmp(argv[1], name_function_map[i].name) == 0)
        {
            // Found the function, call it
            name_function_map[i].function();

            // No need to search any more, unless there are duplicates?
            break;
        }
    }
}

// The definitions (implementations) of the functions, as before...
...
Run Code Online (Sandbox Code Playgroud)


Clo*_*oud 5

是的,但你可能不希望这样做是因为你的目标(即避免switch陈述).从另外一个SO回答(通过编译gcc -std=c99 -Wall -rdynamic ds.c -o ds -ldl,假设文件名是ds.c)(请记住,你需要知道函数签名,即:返回类型加参数;提前).

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

void hello ()
{
    printf ("hello world\n");
}

int main (int argc, char **argv)
{
    char *buf = "hello";
    void *hndl = dlopen (NULL, RTLD_LAZY);
    if (!hndl) { fprintf(stderr, "dlopen failed: %s\n", dlerror()); 
        exit (EXIT_FAILURE); };
    void (*fptr) (void) = dlsym (hndl, buf);
    if (fptr != NULL)
        fptr ();
    else
        fprintf(stderr, "dlsym %s failed: %s\n", buf, dlerror());
    dlclose (hndl);
}    
Run Code Online (Sandbox Code Playgroud)

你最好只创建一个专门提供函数/字符串映射的函数.我提供的例子只是为了证明你所要求的东西可以做到.只因为你可以,并不意味着你应该.

修改示例

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

void foo1(void);
void foo2(void);
void foo3(void);

int main (int argc, char **argv)
{

    /* dlopen() self. */
    void *hndl = dlopen (NULL, RTLD_LAZY);
    if (!hndl) { fprintf(stderr, "dlopen failed: %s\n", dlerror()); 
        exit (EXIT_FAILURE); };

    /* Attempt to find symbols and call them. */
    for (int i = 0; i < argc; i++) {
        void (*fptr) (void) = dlsym(hndl, argv[i]);
        if (fptr != NULL)
            fptr();
        else
            fprintf(stderr, "dlsym %s failed: %s\n", argv[i], dlerror());
    }

    /* Cleanup. */
    dlclose (hndl);

    return 0;
}

void foo1()
{
    printf("hello world\n");
}

void foo2()
{
    printf("Mello world\n");
}

void foo3()
{
    printf("Jello world\n");
}
Run Code Online (Sandbox Code Playgroud)

样品运行

./ds foo1 foo2 foo3 foo1
dlsym ./ds failed: ./ds: undefined symbol: ./ds
hello world
Mello world
Jello world
hello world
Run Code Online (Sandbox Code Playgroud)