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

Declare function in static library, define it in application that uses that same library

本文关键字:定义 应用程序 声明 静态 函数      更新时间:2023-10-16

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

因此,作为示例,将其想象为静态库:

在 foo.h 中:

void foo();

在foo.cpp:

#include "foo.h"
int main() {
foo();
return 0;
}

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

在应用中.cpp:

#include "foo.h"
void foo() {
// Do something here...
}

我想这一定是 例如 Win32 API 对其WinMain()函数所做的,它基本上取代了通常的main().这是如何工作的?在上面的例子中,静态库当然不会编译,因为undefined referencefoo()

是的,这是可能的。 你已经知道怎么做。

你的困惑在于

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

但是"未定义的引用"不是编译错误 - 它是由链接器生成的。 静态库只是已编译对象文件的未链接集合。 (加上索引,因此链接器可以有效地找到它需要的对象文件,而无需扫描每个对象文件(

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

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

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

//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;
}

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

你已经在隐式地这样做了。您拥有的库具有对标头中声明的foo()的引用。

如果应用程序没有提供foo()的定义,你最终会得到一个链接错误。
要解决此问题,库的用户需要提供foo()的定义。

但是,可以编译静态库,仅当使用它创建可执行文件或共享库时,才会发生链接器错误。

您应该在头文件中记录它。

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

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

顺便说一下,lex库还包含main的定义,所以这也并非闻所未闻。