如何检查函数是否存在于C / C ++中

在我的代码中的某些情况下,我最终调用该函数,只有当该函数被定义,否则我不应该。 我怎么能做到这一点?

like: if (function 'sum' exists ) then invoke sum () 

可能是另一种方式来问这个问题是:如何确定函数是否定义在运行时,如果是的话,然后调用。

Solutions Collecting From Web of "如何检查函数是否存在于C / C ++中"

虽然其他答复是有用的建议( dlsym ,函数指针,…),您不能编译一个C ++代码引用一个不存在的函数。 最低限度,功能必须被宣布 ; 如果不是,你的代码将不能编译。 如果没有任何东西(一个编译单元,一些目标文件,一些库) 定义了这个函数,那么链接器会抱怨(除非它很弱,见下文)。

但是你应该真的解释你为什么这么问。 我无法猜测,而且有一些方法可以实现你未说明的目标。

请注意, dlsym通常需要没有名称修饰的函数,即声明为extern "C"

如果使用GCC在Linux上进行编码,则可能还会在声明中使用weak 函数属性 。 链接器然后将未定义的弱符号设置为空。

附加物

如果你从一些输入中获得函数名,你应该知道只有一部分函数可以这样调用(如果你调用一个任意的函数,它会崩溃的!),你会更好地明确地构造那个子集。 然后可以使用std::mapdlsym (将子集中的每个函数声明为extern "C" )。 注意,具有NULL路径的dlopen给出了主程序的一个句柄,你应该使用-rdynamic来使它正常工作。

你真的只想通过他们的名字来调用一个恰当定义的函数子集。 例如,你可能不想这样叫abortexitfork

NB。 如果你知道被动函数的签名,你可能需要使用libffi来调用它。

当你声明“总和”时,你可以声明如下:

 #define SUM_EXISTS int sum(std::vector<int>& addMeUp) { ... } 

那么当你来使用它时,你可以去:

 #ifdef SUM_EXISTS int result = sum(x); ... #endif 

我猜你是从一个脚本语言来的,在运行时所有的东西都完成了。 用C ++来记住的主要是两个阶段:

  • 编译时间
    • 预处理器运行
    • 模板代码变成真正的源代码
    • 源代码被转换成机器码
  • 运行
    • 机器码运行

所以所有的#定义和类似的事情发生在编译时。

….

如果你真的想在运行时完成这些工作,你可能会对使用某些组件架构产品感兴趣。

或者可能是一种插件类型的架构是你所追求的。

使用指针函数。

  //initialize typedef void (*PF)(); std::map<std::string, PF> defined_functions; defined_functions["foo"]=&foo; defined_functions["bar"]=&bar; //if defined, invoke it if(defined_functions.find("foo") != defined_functions.end()) { defined_functions["foo"](); } 

我怀疑这张海报实际上是在寻找更多的东西,按照SFINAE检查/发送的方式。 使用C ++模板,可以定义模板函数,调用所需函数(如果存在)和不执行任何操作(如果函数不存在)。 然后,您可以使第一个模板取决于所需的功能,从而使该模板在该函数不存在时不合格。 这是有效的,因为在C ++模板替换失败不是一个错误(SFINAE),所以编译器将回落到第二种情况(例如,什么也不能做)。

在这里看到一个很好的例子: 是否可以编写一个模板来检查函数的存在?

如果你知道你想调用的函数库,那么你可以使用dlsym()dlerror()来找出它是否存在,以及函数的指针是什么。

编辑:我可能不会实际使用这种方法 – 相反,我会建议Matiu的解决方案,因为我认为这是更好的做法。 但是, dlsym()不是很知名,所以我想我会指出。

使用GCC你可以:

 void func(int argc, char *argv[]) __attribute__((weak)); // weak declaration must always be present // optional definition: /*void func(int argc, char *argv[]) { printf("ENCONTRE LA FUNC\n"); for(int aa = 0; aa < argc; aa++){ printf("arg %d = %s \n", aa, argv[aa]); } }*/ int main(int argc, char *argv[]) { if (func){ func(argc, argv); } else { printf("no encontre la func\n"); } } 

如果你取消注释功能,它将运行,否则它将打印“没有encontre la func \ n”。

换句话说,如果你使用c ++ 11,将会使用函子:

你需要把它放在你的文件的开头:

 #include <functional> 

函子的类型以这种格式声明:

 std::function< return_type (param1_type, param2_type) > 

你可以添加一个变量来保存一个函数,如下所示:

 std::function<int(const std::vector<int>&)> sum; 

为了方便起见,缩短参数类型:

 using Numbers = const std::vectorn<int>&; 

然后你可以用下面的任何一个来填充函子var:

拉姆达:

 sum = [](Numbers x) { return std::accumulate(x.cbegin(), x.cend(), 0); } // std::accumulate comes from #include <numeric> 

一个函数指针:

 int myFunc(Numbers nums) { int result = 0; for (int i : nums) result += i; return result; } sum = &myFunc; 

一些“绑定”创造了:

 struct Adder { int startNumber = 6; int doAdding(Numbers nums) { int result = 0; for (int i : nums) result += i; return result; } }; ... Adder myAdder{2}; // Make an adder that starts at two sum = std::bind(&Adder::doAdding, myAdder); 

然后最后使用它,这是一个简单的if语句:

 if (sum) return sum(x); 

总之,仿函数是指向函数的新指针,但它们更通用。 如果编译器足够肯定,可能实际上是内联的,但通常与函数指针相同。

当与std :: bind和lambda结合使用时,它们比旧式的C函数指针更优越。

但请记住,他们在C ++ 11及以上环境中工作。 (不在C或C ++ 03中)。

您可以使用#pragma weak来支持它的编译器(请参阅弱符号 wikipedia条目)。

这个例子和评论来自“共享库的内幕”和动态加载 :

 #pragma weak debug extern void debug(void); void (*debugfunc)(void) = debug; int main() { printf(“Hello World\n”); if (debugfunc) (*debugfunc)(); } 

你可以使用弱的编译指令强制链接器忽略未解决的符号[..]程序编译和链接是否调试()实际上是在任何目标文件中定义的。 当符号保持未定义时,链接器通常用0替换它的值。所以,这种技术对于程序来说可以调用可选代码,而不需要重新编译整个应用程序。