我想在静态库中声明一个名为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 reference
foo()
。
是的,这是可能的。 你已经知道怎么做。
你的困惑在于
静态库当然不会编译,因为"未定义的引用">
但是"未定义的引用"不是编译错误 - 它是由链接器生成的。 静态库只是已编译对象文件的未链接集合。 (加上索引,因此链接器可以有效地找到它需要的对象文件,而无需扫描每个对象文件(
当链接器运行时,它将同时提供应用程序对象和库,并且不会未解决任何内容。
动态库是通过链接步骤创建的;静态库不是。
一般来说,这种功能通常是通过函数指针实现的。
//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
的定义,所以这也并非闻所未闻。