【问题标题】:calling function on runtime in c [duplicate]在c中运行时调用函数[重复]
【发布时间】:2013-12-30 20:47:42
【问题描述】:

如何在运行时调用函数?我想知道是否可以不使用 ifswitch 来调用它,

if(arg[1] == something) //Now what I'm looking for
      call_function;

下面是我正在寻找的,它是使用 arg 调用函数 print?

#include <stdio.h>

void print()
{

    printf("print function called\n");
}

int main(int argc, char *argv[])
{
    argv[1] to call the print function 
}

那么我可以这样称呼它,

 ./a.out print

【问题讨论】:

标签: c function-pointers


【解决方案1】:

这不是微不足道的或自动的。函数名只存在于语言中,不存在于执行程序中。您必须自己提供从合适的字符串常量到函数的映射(或使用一些现有的机制,如 Posix 上的dlsym)。您可以通过函数指针引用该函数:

typedef void (void_function)(void);

extern void print(void);
extern void foo(void);
extern void bar(void);

void_function my_little_functions[] = { print, foo, bar };


int main(int argc, char * argv[])
{
    if (strcmp(argv[1], "print") == 0) { my_little_functions[0](); }
    // ...
}

这仅用于说明;您应该实现一些合适的函数指针值关联查找结构,而不是一系列条件语句。

(在 C++ 中,这将是 std::unordered_map&lt;std::string, void_function *&gt;。在 C 中,您必须找到自己的。)

【讨论】:

  • “函数名只存在于语言中,不存在于执行程序中”——如果你strip。如果您不这样做,则必须以某种方式保留非static 函数名称。 dlsym(handle, argv[1]) 对于初学者来说效果很好。
  • @H2CO3: 非标准 :-) 动态链接(不幸的是)不是语言标准的一部分。 Posix 至少在某些方面做出了额外的保证。不过,我很确定您最终可以自定义和重写符号导出名称,因此源代码和您可以放入 dlsym 的名称之间的联系是暂时的。
  • @H2CO3:事实上,从头开始。我认为我的立场是共享库二进制文件的供应商只需告诉您一个名称列表以及可与dlsym 一起使用的函数类型。这说明可能以头文件的形式发生,但不是必须的。
  • 我知道这是非标准的,你说得对,将函数名称告知用户绝对是更好的做法,但“不可能”完全是错误的。无论如何,OP 并没有写到他需要一个在任何情况下都可以在任何操作系统上运行的解决方案,而不依赖任何外部库......
  • @H2CO3:如果您愿意的话,我想您可以将该映射外包给dlsym...
【解决方案2】:

如果您不是在寻找“纯 C”解决方案,那么您可以使用操作系统的 API 为您进行映射。在 POSIX 下(编译并运行):

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

void foo(void)
{
    printf("foo\n");
}

void bar(void)
{
    printf("bar\n");
}


void baz(void)
{
    printf("baz\n");
}

int main(int argc, char *argv[])
{
    void *hndl = dlopen(NULL, RTLD_LAZY);
    void (*fn)(void) = dlsym(hndl, argv[1]);

    if (fn) {
        fn();
    } else {
        printf("Function %s() not found\n", argv[1]);
    }

    return 0;
}

【讨论】:

    【解决方案3】:

    嗯,其实是有办法的……

    在运行时,您可以编写一个包含函数定义的 .c 文件,并在 main 中编写对argv[1] 中命名的函数的调用。然后您可以调用编译器(gcc-linux 或 cl-windows 或其他)(通过system(command))来生成可执行文件。然后您调用该可执行文件(通过system(command))并完成工作。

    什么?我没有说这是一种实用的方式,我只是说这是一种方式。


    证明这确实有效:

    #include <stdio.h>
    #include <stdlib.h>
    
    const char file_includes[] = "#include <stdio.h>\n";
    const char file_functions[] = 
      "void print() {\n"
      "    printf(\"print function called\\n\");\n"
      "}\n"
      "void print2() {\n"
      "    printf(\"second print function called\\n\");\n"
      "}\n";
    
    const char file_main_prolog[] = "int main() {\n";
    const char file_main_epilog[] = "  return 0;\n}\n";
    
    
    int main(int argc, char *argv[]) {
      if (argc < 2) {
        printf("invalid program arguments\n");
        return 1;
      }
    
      FILE *fout = fopen("function_call.c", "w");
    
      fprintf(fout, "%s", file_includes);
      fprintf(fout, "%s", file_functions);
      fprintf(fout, "%s", file_main_prolog);
      fprintf(fout, "  %s();\n", argv[1]);
      fprintf(fout, "%s", file_main_epilog);
    
      fclose(fout);
    
      system("gcc -o function_call function_call.c");
      system("./function_call");
    
      return 0;
    }
    

    这可以在安装了 gcc 的 linux 下工作。您可以使用参数printprint2 运行此程序,您将分别得到print function calledsecond print function called

    【讨论】:

      猜你喜欢
      • 2014-12-03
      • 1970-01-01
      • 2016-11-21
      • 2018-08-07
      • 2021-03-16
      • 2013-07-09
      • 1970-01-01
      • 2013-06-12
      • 2012-09-07
      相关资源
      最近更新 更多