在静态库中声明函数,在使用相同库的应用程序中定义它

时间:2017-08-24 19:14:46

标签: c++ c

我想在静态库中声明一个名为foo()的函数,并从静态库中调用它。但是,我想强制应用程序的用户提供foo()的定义。在C / C ++中是否可以这样?

例如,假设这是静态库:

在foo.h中:

void foo();

在foo.cpp中:

#include "foo.h"

int main() {
   foo();
   return 0;
}

然后在使用此静态库的应用程序中:

在app.cpp中:

#include "foo.h"

void foo() {
    // Do something here...
}

我想这必须是例如Win32 API使用WinMain()函数,它实际上取代了通常的main()。这怎么工作呢?在上面的示例中,由于undefined referencefoo(),静态库当然无法编译。

4 个答案:

答案 0 :(得分:8)

是的,有可能。你已经知道了。

你的困惑在于

  

静态库当然不能编译,因为"未定义的引用"

但"未定义的参考"不是编译错误 - 它是由链接器生成的。静态库只是一个未链接的编译对象文件集合。 (加上可能是一个索引,因此链接器可以在不扫描每个文件的情况下有效找到所需的目标文件)

当链接器运行时,它将同时提供应用程序对象和库,并且不会有任何内容未解析。

通过链接步骤创建动态库;静态库不是。

答案 1 :(得分:3)

  

但是,我想强制应用程序的用户提供foo()的定义。在C / C ++中是否可以这样?

你已经暗中这样做了。您拥有的库在标题中声明了foo()的引用。

如果应用程序未提供foo()的定义,则最终会出现链接错误 要解决此问题,您图书馆的用户需要提供foo()的定义。

您的静态库可以编译,只有在使用它创建可执行文件或共享库时才会发生链接器错误。

您应该在头文件中记录。

答案 2 :(得分:2)

一般来说,这种功能通常是通过函数指针实现的。

//header.h
typedef int(*add_func)(int, int);

int perform_add(int a, int b, add_func func) {
    return func(a,b);
}

//In User .cpp file
#include<Header.h>

int my_add_func(int a, int b) {
    return a; //Ooooh, edgy!
}

int my_other_add_func(int a, int b) {
    return a + 2 * b; //Don't cut yourself with that edge!
}

int main() {
    int val = perform_add(1, 5, my_add_func);
    val = perform_add(val, val, my_other_add_func);
    return 0;
}

在C ++中,我们通常使用std::function来表示这些指针,因为它们更容易阅读,并且还可以保存函子和lambda。

//header.h
typedef std::function<int(int,int)> add_func;

int perform_add(int a, int b, add_func const& func) {
    return func(a,b);
}

//In User .cpp file
#include<Header.h>

int my_add_func(int a, int b) {
    return a; //Ooooh, edgy!
}

int my_other_add_func(int a, int b) {
    return a + 2 * b; //Don't cut yourself with that edge!
}

int main() {
    int val = perform_add(1, 5, my_add_func);
    val = perform_add(val, val, my_other_add_func);
    //The following would not have compiled if we just used function pointers.
    val = perform_add(val, 17, [val](int a, int b) {return a + b + val;});
    return 0;
}

答案 3 :(得分:1)

在库中保留未定义的函数并期望应用程序提供它,在技术上没有任何错误。这实际上是由至少一个名为lex的主流产品完成的(您的计算机可能有一个名为flex的免费实现)。这不是一个好的风格,lex / flex继续使用它主要是为了向后兼容。

建议在运行时将用户函数作为回调传递给库代码,而不是在链接时将它们绑定。

顺便提一下,lex库还包含main的定义,所以这也不是闻所未闻的。