7

我正在为几个编译器构建一个 C 项目,其中一些是旧版编译器,它们似乎没有链接时间内联支持,因此将static inline函数直接放在头文件中并且实际上让每个翻译单元都有自己的副本似乎是合乎逻辑的。

另外,我需要确保某些函数是内联的,以便在某些低级中断处理程序中调用时不会调用其他函数(即更改 CPU 寄存器),所以这不仅仅是让编译器选择它是否会影响性能.

但是,我的一位同事告诉我,这是一件不寻常的事情,我应该避免这样做。在项目的这一点上,我可能仍然可以重新安排所有内容,所以我想确认如果我们决定使用标题内联,从长远来看,我们是否会面临一些问题?

4

3 回答 3

5

来自 n1570(最新的公共 C11 草案),§6.7.4:

  1. 使用函数说明符声明的inline函数是内联函数。使函数成为内联函数意味着对函数的调用尽可能快。此类建议的有效程度由实施定义。

下一节将详细介绍链接,但上面这段话基本上是 C 标准要说的所有内容inline。请注意,这如何为实现提供各种自由,包括完全忽略inline.

因此,仅使用标准 C,您最终可能会得到以正常方式调用的函数的多个实例(每个翻译单元一个)。这通常不是您想要的,因为它结合了两个缺点(重复代码函数调用的开销)。所以我认为标准 Cinline只对单个翻译单元私有的函数有用。即使这样,您也可以假设一个好的优化编译器会自动选择内联候选对象,而无需显式的inline.

另一方面,如果您的编译器提供了一种实际强制内联函数的方法(根据您的注释,说明_inline符会为您的编译器执行此操作),那么将这些函数放在头文件中是安全的。但请注意,它绝不是便携式的。

正如cmaster评论的那样,您可以使用 类似功能的宏来实现一种“手动内联”,而不是一种可移植的解决方案。

于 2017-07-20T07:51:19.077 回答
3

根据对问题的评论,static _inline在头文件中定义函数是这个特定编译器的方法,编译器文档的引用很清楚。

您以后可能面临的问题是它是特定编译器的特定扩展,与标准 inline说明符不同。正如 Felix 所说,该标准允许实现选择它如何实现内联,特别是,忽略说明符仍然是一致的:

使函数成为内联函数意味着对函数的调用尽可能快。此类建议的有效程度由实施定义

话虽如此,语义似乎相同(来自 C99 的 1256 草案或 C11 的 1570 草案):

6.7.4 函数说明符
...
任何具有内部链接的函数都可以是内联函数。对于具有外部链接的函数,适用以下限制: 如果函数使用内联函数说明符声明,则它也应在同一翻译单元中定义。如果翻译单元中函数的所有文件范围声明都包含不带 extern 的内联函数说明符,则该翻译单元中的定义是内联定义。内联定义不为函数提供外部定义,也不禁止在另一个翻译单元中进行外部定义。内联定义提供了外部定义的替代方案,翻译器可以使用它来实现对同一翻译单元中函数的任何调用。

因此,由于常见的实现确实尊重说明inline符,我认为可移植性的风险是有限的

于 2017-07-20T08:21:04.407 回答
0

没有必要将函数声明static inlineISO 9899保证函数不会被导出到链接器,因为您没有extern在翻译单元内的任何内联函数声明中使用存储类说明符。

换句话说,如果您简单地将其声明为,则从外部看不到inline aaa该符号。aaa

我引用自6.7.4 Function specifiers

如果翻译单元中函数的所有文件范围声明都包含内联函数说明符而没有 extern,则该翻译单元中的定义是内联定义。内联定义不为函数提供外部定义,也不禁止在另一个翻译单元中进行外部定义。

emacs 使用这种内联技术,在lisp.h定义 lisp 对象的标头中,我引用了 emacs 的源代码:

一些操作非常常见,以至于它们被实现为宏,而不是函数,因为否则在没有优化的情况下使用 GCC 编译时运行时性能会受到太大影响。
无需内联所有内容,只需内联会导致严重性能问题的操作即可。

于 2017-07-20T09:39:39.290 回答