嵌入式系统中的函数指针是否有用?

时间:2011-01-29 10:04:12

标签: embedded functor

在一次采访中,他们问我在编写嵌入式系统的代码时,使用函数指针是否有益(在速度方面)?我不知道嵌入式系统,所以无法回答这个问题。只是一个阴天或模糊的答案。 那么真正的好处是什么?速度,可读性,维护,成本?

10 个答案:

答案 0 :(得分:21)

我想也许Viren Shakya的回答错过了面试官试图引出的观点。在某些结构中,使用函数指针可以加速执行。例如,如果你有一个索引,使用它来索引一个函数指针数组可能比一个大开关更快。

但是,如果您要将静态函数调用与通过指针调用进行比较,那么Viren正确地指出还有一个额外的操作来加载指针变量。但没有人合理地尝试以这种方式使用函数指针(只是作为直接调用的替代方法)。

通过指针调用函数不是直接调用的替代方法。所以,“优势”的问题是有缺陷的;它们用于不同的环境,通常用于简化其他代码逻辑和控制流程,而不仅仅是避免静态函数调用。它们的用处在于,要调用的函数的确定是在运行时由代码动态执行,而不是由链接器静态执行。从这个意义上讲,它们在嵌入式系统中当然是有用的,但不是出于与嵌入式系统有关的任何原因。

答案 1 :(得分:17)

有很多用途。

嵌入式系统中函数指针的最重要用途是创建向量表。许多MCU架构使用位于NVM中的地址表,其中每个地址指向ISR(中断服务例程)。这样的向量表可以用C语言编写为函数指针数组。

函数指针对回调函数也很有用。作为现实世界的一个例子,前几天我正在为片上实时时钟编写驱动程序。芯片上只有一个时钟,但我需要很多定时器。这是通过为每个软件定时器保存一个计数器来解决的,该计数器由实时时钟中断增加。数据类型如下所示:

typedef struct
{
  uint16_t counter;
  void (*callback)(void);

} Timer_t;

当硬件定时器与软件定时器相同时,通过与计数器一起存储的函数指针调用用户指定的回调函数。像上面这样的东西是嵌入式系统中非常常见的结构。

在创建引导加载程序等时,函数指针也很有用,您将在运行时将代码写入NVM,然后调用它。您可以通过函数指针执行此操作,但不能通过链接函数执行此操作,因为代码实际上并不在链接时。

如上所述,函数指针当然对许多优化很有用,比如优化掉每个“case”是相邻数字的switch语句。

答案 2 :(得分:7)

另一件需要考虑的事情是,这个问题将是展示您在开发过程中如何制定设计决策的好机会。我能想象给出的一个回应是转过身来考虑你的实施方案。从Casey和Lundin的答案中得到一个页面,我发现回调函数非常有用,可以将模块彼此隔离并使代码更改更容易,因为我的代码处于永久原型设计阶段,而且事情变化很快且经常发生。我目前关注的是易于开发,而不是速度。

在我的情况下,我的代码通常涉及具有多个模块,这些模块需要相互发信号以同步操作顺序。以前我把它作为一整套标志和数据结构实现了extern链接。通过这种实现,两个问题通常会占用我的时间:

  1. 由于任何模块都可以触及外部变量,因此我花了很多时间来监管每个模块,以确保这些变量按预期使用。
  2. 如果另一位开发人员引入了新的标志,我发现自己潜入了多个模块,寻找原始声明和(希望)评论中的用法说明。
  3. 使用回调函数,问题就会消失,因为函数成为信号机制,并且您可以利用这些优势:

    1. 模块交互由功能接口强制执行,您可以测试前/后条件。
    2. 对全局共享数据结构的需求较少,因为回调用作外部模块的接口。
    3. 减少耦合意味着我可以相对容易地换掉代码。
    4. 目前,即使使用了所有额外的函数调用,我的设备仍然能够充分发挥性能。当性能开始成为一个更大的问题时,我会考虑我的替代方案。

      回到面试问题,尽管你可能不熟悉功能指针的细节,但我认为你仍然是一个有价值的候选人,因为你知道你在认识到这一过程中做出的权衡。设计过程。

答案 3 :(得分:5)

答案 4 :(得分:3)

我会说它们在任何环境中都是有益的(在速度方面),而不仅仅是嵌入式。这个想法是,一旦指针指向正确的函数,就不需要进一步的决策逻辑来调用该函数。

答案 5 :(得分:2)

是的,它们很有用。我不确定面试官会得到什么。基本上,如果嵌入或不嵌入系统则无关紧要。除非你有严重限制的堆栈。

  • 速度不,最快的系统将是单个功能,并且仅使用全局变量和分散的goto。祝你好运。
  • 可读性是的,它可能会让一些人感到困惑,但总体来说某些代码在函数指针中更具可读性。它还允许您增加源代码各个方面之间的关注点分离。
  • 可维护性是的,使用函数指针,您将拥有更少的条件,更少的重复代码,更多的代码分离,以及通常更正交的软件。

答案 6 :(得分:1)

函数指针的一个负面部分是它们永远不会在调用中内联。这可能是有益的,也可能不是有益的,这取决于您是在编译速度还是大小。如果是后者,它们应该与正常的函数调用没有区别。

答案 7 :(得分:1)

函数指针的另一个缺点(关于虚函数,因为它们只是核心级别的函数指针):

制作内联和&& virtual将强制编译器创建相同函数的外联副本。这将增加最终二进制文件的大小(假设已经大量使用它)。

经验法则:1:不要内联虚拟呼叫

答案 8 :(得分:1)

这是一个棘手的问题。有些行业禁止使用指针。

答案 9 :(得分:0)

让我们看看......

速度(比如我们在ARM上):然后(理论上):

(正常函数调用ARM指令大小)< (功能指针调用设置指令大小)

由于它们是设置函数指针调用的附加级别的间接,因此它将涉及额外的ARM指令。

PS:正常函数调用:使用BL设置的函数调用。

PSS:不知道它们的实际尺寸,但应该很容易验证。