如果 C 函数仍然可以间接执行(通过回调函数),那么将 C 函数声明为静态是不好的做法吗?

Bre*_*ett 10 c c++ embedded linker compiler-optimization

我有一个用于嵌入式系统 ( foo.c, foo.h)的 C 模块,其中包含一个my_driver_fn()从 API 角度来看局部范围的函数(例如,不在foo的公共标头中:任何其他使用其 API 的代码#include "foo.h" 都不应被允许调用此函数)。假设my_driver_fn()是可重入的。

然而,foo使用一个libdostuff需要用一些用户提供的回调函数(架构/硬件特定的东西)初始化的库才能在任何平台上正常工作。在 中foomy_driver_fn上面提到的将是有问题的功能之一......需要libdostuff,但不是任何使用foo.

对于这些回调函数(my_driver_fn()被声明为staticinside foo.c?鉴于它的地址被提供给libdostuff并且它是“间接地”调用(虽然从不直接)?

注意:我碰巧同时写了fooand libdostuff,我想知道用户提供的函数extern在链接时被纯粹解析,或者通过libdostuff用户提供的回调表传递到初始化中是否更有意义函数(例如libdostuff_init(CallbackTable *user_callbacks)whereCallbackTable有一个将被初始化为指向的函数指针my_driver_fn

M.M*_*M.M 13

在我看来,这是一个很好的做法。该static指名称的知名度,而不是其他。

如果其他翻译单元不需要使用该名称,则对其进行标记可以static降低在外部可见函数的“命名空间”中发生冲突的风险。


Lun*_*din 8

这是一种很好的做法,并且没有诸如定义不明确的行为之类的负面影响。

使用 的原因有很多static,比如减少命名空间污染和避免意外/故意调用。但主要原因其实是私有封装设计和自文档化代码——将函数保留在它们所属的模块中,这样外界就不必担心如何以及何时调用它们。他们应该只关心您在公共头文件中声明的外部链接函数。

例如,这正是您在嵌入式系统中设计 ISR 的方式。它们应始终声明static并放置在控制 ISR 相关硬件的驱动程序中。与 ISR 的所有通信,包括竞争条件保护,都应封装在该驱动程序中。调用应用程序从不直接与 ISR 对话,不需要担心重入等。DMA 缓冲区也是如此。

作为一个例子,我总是为我所有的 MCU 项目设计一个循环定时器驱动程序,其中调用者的 API 允许他们注册简单的回调函数。然后,计时器驱动程序在计时器结束时从 ISR 内部调用回调。然后,这可以用作所有需要计时器的低优先级任务的通用计时器:延迟,去抖动等。 然后调用者只需要负责任地将回调函数保持在最小并以毫秒为单位指定时间,但调用者不知道也不关心定时器硬件,定时器硬件对它执行的回调一无所知。双向松耦合。此计时器 API 还用作 HAL,因此您可以将代码移植到另一个 MCU,而无需更改调用者代码 - 只需更改底层驱动程序。