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

Is it bad practice to declare a C function as static if it can still be executed indirectly (through a callback function)?

本文关键字:函数 静态函数 是否是 声明 一种 执行 如果 回调      更新时间:2023-10-16

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

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

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

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

(

在我看来,这是很好的做法。static是指名称的可见性,仅此而已。

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

这是很好的做法,没有负面的副作用,比如定义不清的行为。

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

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

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

这是很好的做法。 它确保函数只能由显式提供回调的代码调用。 如果它有外部联系,任何东西都可以称之为它,无论它是否有意义。 滥用显然不是不可能,但确实使意外更难做到。