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

时间:2012-01-11 05:41:24

标签: c++ c linux

我的代码中的某些情况,我最终只在定义了该函数时调用该函数,否则我不应该。我怎样才能做到这一点?

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

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

9 个答案:

答案 0 :(得分:12)

当您声明'sum'时,您可以声明它:

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

然后当你来使用它时你可以去:

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

我猜你是来自一种脚本语言,其中的一切都是在运行时完成的。使用C ++需要记住的主要问题是两个阶段:

  • 编译时间
    • 预处理器运行
    • 模板代码变成了真正的源代码
    • 源代码在机器代码中打开
  • 运行时
    • 运行机器代码

因此所有#define和类似的事情都发生在编译时。

...

如果您真的想在运行时完成所有操作......您可能有兴趣使用其中的一些component architecture products

或许plugin kind of architecture就是你所追求的。

答案 1 :(得分:10)

使用函数指针。

 //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"]();
 }

答案 2 :(得分:10)

虽然其他回复是有用的建议(dlsym,函数指针,...),但无法编译 C ++代码引用不存在的函数。至少,该函数必须声明;如果不是,您的代码将无法编译。如果没有(编译单元,某个目标文件,某些库)定义该函数,链接器会抱怨(除非它很弱,见下文)。

但是你应该解释为什么要问这个问题。我无法猜测,并且有一些方法可以达到你未说明的目标。

请注意,dlsym通常需要没有name mangling的函数,即声明为extern "C"

如果在使用GCC的Linux上进行编码,您也可以在声明中使用weak function attribute。然后链接器将未定义的弱符号设置为null。

附加物

如果你从某个输入中获取函数名,你应该知道只有一部分函数应该以这种方式调用(如果你不小心调用任意函数,它会崩溃!)你会更明确地明确构造那个子集。然后,您可以使用std::mapdlsym(声明extern "C"子集中的每个函数)。请注意,带有dlopen路径的NULL会为主程序提供一个句柄,您应该将其与-rdynamic链接以使其正常工作。

你真的想通过他们的名字只调用一个适当定义的函数子集。例如,您可能不希望以abortexitfork的方式调用。

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

答案 3 :(得分:10)

我怀疑海报实际上是在寻找SFINAE检查/派遣的更多内容。使用C ++模板,可以定义模板函数,一个调用所需函数(如果存在)和一个不执行任何函数(如果函数不存在)。然后,您可以使第一个模板取决于所需的函数,以便在函数不存在时模板格式错误。这是有效的,因为在C ++中模板替换失败不是错误(SFINAE),因此编译器将回退到第二种情况(例如它什么都不做)。

请点击此处查看优秀示例:Is it possible to write a template to check for a function's existence?

答案 4 :(得分:8)

使用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");
    }
}

如果取消注释func,它将运行它,否则它将打印&#34; no encontre la func \ n&#34;。

答案 5 :(得分:4)

如果您知道要调用的函数是哪个库,那么您可以使用dlsym()dlerror()来确定它是否在那里,以及该函数的指针是什么是

编辑:我可能实际上不会使用这种方法 - 相反,我会推荐Matiu的解决方案,因为我认为这是更好的做法。但是,dlsym()并不是很有名,所以我想我会指出它。

答案 6 :(得分:2)

另一种方式,如果你使用的是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>&;

然后你可以用以下任何一个填充functor var:

一个lambda:

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;

'bind'创造的东西:

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中)。

答案 7 :(得分:1)

您可以将#pragma weak用于支持它的编译器(请参阅weak symbol维基百科条目)。

此示例和评论来自The Inside Story on Shared Libraries and Dynamic Loading

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

您可以使用弱pragma强制链接器忽略未解析   符号[..]程序编译并链接是否debug()   实际上是在任何目标文件中定义的。当符号仍然存在时   undefined,链接器通常用0替换它的值。所以,这个   技术可以是程序调用可选代码的有用方法   这不需要重新编译整个应用程序。

答案 8 :(得分:0)

在 C++ 中,用于检查成员是否存在的 the trick 的修改版本应该在编译时而不是运行时为您提供您正在寻找的内容:

#include <iostream>
#include <type_traits>

namespace
{
    template <class T, template <class...> class Test>
    struct exists
    {
        template<class U>
        static std::true_type check(Test<U>*);

        template<class U>
        static std::false_type check(...);

        static constexpr bool value = decltype(check<T>(0))::value;
    };
    
    template<class U, class = decltype(sum(std::declval<U>(), std::declval<U>()))>
    struct sum_test{};
    
    template <class T>
    void validate_sum()
    {
        if constexpr (exists<T, sum_test>::value)
        {
            std::cout << "sum exists for type " << typeid(T).name() << '\n';
        }
        else
        {
            std::cout << "sum does not exist for type " << typeid(T).name() << '\n';
        }
    }
    
    class A {};
    class B {};
    
    void sum(const A& l, const A& r); // we only need to declare the function, not define it
}

int main(int, const char**)
{
    validate_sum<A>();
    validate_sum<B>();
}

这是使用 clang 的输出:

sum exists for type N12_GLOBAL__N_11AE
sum does not exist for type N12_GLOBAL__N_11BE

我应该指出,当我使用 int 而不是 A 时发生了奇怪的事情(sum() 必须在 sum_test 之前声明才能使 exists 工作,所以可能 {{1 }} 不是正确的名称)。某种模板扩展,当我使用 A 时似乎不会引起问题。我猜它与 ADL 相关。