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

问题描述 投票:4回答:2

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

但是,foo使用库libdostuff,该库需要用一些用户提供的回调函数(体系结构/硬件特定的东西)进行初始化,以使其在任何平台上都能正常工作。在foo中,上面提到的my_driver_fn将是有问题的功能之一……需要libdostuff,但不是使用foo的任何人。

对于这些回调函数(my_driver_fn()static中被声明为foo.c,这是否是错误的形式,危险的,不利的,以任何方式妨碍编译器或编译器可以利用的未定义行为?给定它的地址提供给libdostuff并且被“间接”调用(尽管从不直接)?

注意:我碰巧同时写了foolibdostuff,我想知道让用户提供的函数在链接时纯粹解析还是传递给extern更有意义? libdostuff通过初始化函数中提供的用户提供的回调表(例如libdostuff_init(CallbackTable *user_callbacks),其中CallbackTable具有要初始化为指向my_driver_fn的函数指针)

c++ c linker embedded compiler-optimization
2个回答
11
投票

我认为这是一种好习惯。 static是指名称的可见性,仅此而已。

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


5
投票

这是一种好习惯,并且没有不良行为,例如行为不明确。

使用static的原因很多,例如减少名称空间污染和避免意外/故意呼叫。但是主要的原因实际上是私有封装设计和自文档代码-将函数保留在它们所属的模块中,因此外界无需担心如何以及何时调用它们。他们只应关心在公共头文件中声明的外部链接功能。

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

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

© www.soinside.com 2019 - 2024. All rights reserved.