从this question跟随我之前问过。我想知道如何在全局范围内定义inline
函数。
我想在test.h中声明inline
函数,在main.c中定义它并从test.c中调用它。
main.c和test.c都是#include "test.h"
(代码示例请点击上面的链接)。
这基本上是某种用户可以启用/禁用的回调函数。并且只有一个文件应该定义函数。
我知道inline
只是对编译器的一个建议,它在现代CPU上没有太大的区别,但这是针对8位微控制器而且确实需要它。
编辑:
我在test.c中有一个函数,它调用这个内联函数。我只想用main.c中定义的函数体替换调用。我希望这是有道理的。
它的工作方式就是这样,你只有一个函数定义,比如它是函数int add(int x, int y);
然后你在main.c
中定义它
main.c中:
int add(int x, int y)
{
return x + y;
}
那么如果你想在另一个c文件中使用它,你只需要这个
test.c的
int add(int x, int y); /* just a declaration, a function prototype */
int addWrapper(int x, int y)
{
return add(x, y);
}
像这样编译它
gcc -Wall -Werror main.c test.c -o some_output_file_name
并且链接器将负责查找函数定义。
如果未在任何已编译的文件中定义该函数,则a
Undefined reference to `int add(int x, int y);' in ...
将发出错误。
如果要强制编译器插入函数体,然后自己插入函数体,请使用预处理器宏
header.h
#define add(x,y) ((x) + (y))
然后
#include "header.h"
int addWrapper(int x, int y)
{
return add(x, y);
}
将用add(x, y)
取代x + y
。
如果该函数返回void
,那么一个很好的技巧就是使用它
#define inlinedFunction(parameters) \
do { \
/* function body here */ \
} while (0)
你应该在宏定义的每一行的末尾添加一个连续反斜杠。
假设你的意思是你所说的,所讨论的函数是一个回调,你不能内联一个回调。它没有意义,回调调用通常是通过函数指针发生的,我不认为你可以期望编译器证明它的值是常量的(并且在编译时已知)以便它可以替换调用内联代码。
大多数8位微控制器代码是用近似于C89的语言编写的(通常有扩展,例如内联汇编),并且inline
直到C99才正式成为C的一部分。因此,首先要确定您正在编译的标准(如果有的话),如果inline
是扩展名(即不是C99内联),请查阅编译器手册。编程手册在编程领域优先于C标准。
每个C99
如果main.c
和test.c
都需要调用相同的函数并且它需要标记为inline
,那么我相信它必须在标题中定义,因为inline
函数不能跨越翻译单元(即“.c”文件)。
例如:
test.h:
static inline int add(int a, int b) { return a + b; }
main.c中:
#include "test.h"
void main(void)
{
int x = add(10,15);
}
test.c的:
#include "test.h"
int test(void)
{
int x = add(10,15);
return x;
}
编辑:有关C99 inline
用法的更好解释,请参见此处:How to declare an inline function in C99 multi-file project?
但是,这会导致生成的对象代码出现各种奇怪的行为。例如,我已经看到来自主要MCU制造商(有意未命名)的编译器在给定的翻译单元中生成inline
函数#included
的目标代码而不是内联它们。该文件包含在几个地方并包含许多功能,因此这导致整个代码库中整体ROM使用量大幅增加,因为链接器也无法删除死代码(请参阅--gc-sections
for gcc
)并且无法提高性能,因为函数是从来没有实际内联,即使它在技术上是正确使用内联。
我们对这个特定问题的解决方案是将所有函数转换为宏(这给出了inline
的性能优势),但另一种方法是从声明中删除inline
并将定义移动到单个.c
文件。
TL; DR:如果将inline
用于MCU,1)请参阅编译器手册,2)密切关注生成的目标代码。
您可以在C中使用inline
关键字,但如果您使用的是GNU GCC编译器,则还需要内联函数为static
函数。因此,您只能在同一源文件中使用这些功能。如果要声明在某个头文件中定义的全局内联函数,并在包含该头文件的源文件上使用它,则可以使用GNU GCC的always_inline
属性,如下所示:
static inline __attribute__((always_inline)) int foo(int a)
{
return a+2;
}
不要忘记在同一个头文件中声明内联函数的主体。