c - 是否有标准方法允许静态库的使用者定义库中使用的函数(C)
问题描述
问题
是否有“惯用”或标准方式(在 C 中)允许静态库的消费者在定义明确的点将自定义代码“注入”到其中,以便提供特定于消费者的行为?
背景
我在一个项目中编写的大量代码中遇到了这样的需求......例如,我正在为能够插入的自定义 SOM 板上的微控制器编写代码各种不同的主板,每个主板上都有各种不同的传感器和执行器。我们编写了一个引导加载程序,根据 SOM 插入的主板,它可以检测并引导知道如何使用该主板的正确应用程序。
所有这些应用程序都可能希望共享公共组件,但也定义自己的非共享自定义组件。
因此,该项目被构造为“多目标项目”,其中我们的组织类似于以下内容:
lib/
somelib1/
somelib2/
common/
chip_drivers // from silicon vendor
SOM_drivers // HW drivers for stuff on the SOM
reuseable_business_logic // don't want to copy-paste into each app
apps/
app1/
app1_layer1/
app1_layer2/
main.c
app2/
app2_layer1/
app2_layer2/
main.c
我想lib/
和common/
目录中的项目应该编译为静态库并链接到两个应用程序图像。但是,如果某些东西common/reusable_business_logic
需要依赖于应用程序“导出”的函数怎么办?大多数reusable_business_logic
代码是真正可移植的,但是它最终可能需要调用一个自定义app_send()
函数,该函数取决于它是链接到 app1 还是 app2(在应用程序层定义)。
尝试的解决方案
我想象这样做的方式是让common/reusable_business_logic
层调用一个未实现的函数,该函数可以在链接时解决。因此,公共层中的函数将在公共头文件中定义extern some_type app_send(some_type)
为extern,然后在整个代码中自由使用。同时,共同业务逻辑的消费者 app1 和 app2 需要自己定义该功能的实现才能构建。
但这感觉混乱和错误。有没有更好或更惯用的方法来完成我打算做的事情?
解决方案
我已经看到这是通过以下两种方式之一完成的:
首先,正如评论中提到的,回调。这是非常广泛使用且易于实现的。在初始化时将函数指针传递给公共代码可能是一种完全有效的方法,尽管它确实引入了可能不需要关注的状态。
其次几乎是您已经尝试过的 - 项目特定的标题。本质上,公共代码只有一个标头/一组标头,声明目标特定代码需要实现的函数的原型(通常与公共代码本身使用的标头分开),并且这些标头由各个实现,每个实现都定义了所需的功能。该库将缺少目标特定函数的定义,但这并没有真正改变任何东西 - 只要在最终可执行文件被链接时对所有使用的函数都有定义,真的应该'不会有任何问题。对于您正在解决的问题,这既不是罕见的解决方案,也不是特别糟糕的解决方案;工具非常明确地支持它,
第二个选项的一个变体是使用弱符号(__attribute__((weak))
至少在 GCC 中声明,并且可能在不同的编译器下以不同的方式声明) - 这使您可以拥有目标特定功能的默认实现,包含在库本身中 - 这确实没有t 改变任何东西,但如果大多数目标只需要“默认”实现,但有些需要特定差异,则可能很有用 - 这样,您可以避免为所有将使用它的实现重写默认值。
当我不得不将第二个选项用于您所描述的情况时,我个人更喜欢第二个选项,因为在运行时出现问题的可能性较低,但在某些情况下,第一个选项可能更灵活,因为函数指针可以被交换以在运行时而不是编译时更改功能。
推荐阅读
- python - 使用套接字的音频聊天
- python-3.x - 我正在尝试在 for 循环中循环遍历随机字典,但不断获得相同的键/值对。我究竟做错了什么?
- flutter - 如何在 Windows 上使用 dart-sdk (dart2native) 和 flutter/dart-sdk?
- vim - 在 vim 中加入文件路径的建议方法
- css - SCSS - 设置、导出和更新变量值
- python - Boto3 无法为 Dev Endpoint Python 指定 Glue 版本
- c# - c# 8 可空 + 字典<>
- python - 使用 Python pandas,我如何创建一个函数来计算代表低于前一行的值的行的比例?
- javascript - 启动另一个时不要隐藏 SweetAlert2
- reactjs - 在从 CDN 加载的 React 中使用外部依赖项