两个 c 文件之间的全局内联函数
global inline function between two c files
继之前问过。我想知道如何在全局范围内定义 inline
函数。
我想在test.h中声明inline
函数,在main.c中定义它从 test.c.
调用
main.c 和 test.c 都是 #include "test.h"
(代码示例请点击上面的 link)。
这基本上是用户可以使用的某种回调函数 enable/disable。并且只有一个文件应该具有函数 defined.
我知道 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
链接器将负责查找函数定义。
如果函数未在任何编译文件中定义,则
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
。
如果函数 returns void
那么一个不错的技巧是使用这个
#define inlinedFunction(parameters) \
do { \
/* function body here */ \
} while (0)
您应该在宏定义的每一行末尾添加一个连续的反斜杠。
大多数 8 位微控制器代码是用类似于 C89 的语言编写的(通常有扩展,例如内联汇编),并且 inline
不是 官方 的一部分C 到 C99。所以首先要确定你正在编译的标准(如果有的话),如果 inline
是一个扩展(即不是 C99 内联),请查阅你的编译器手册。在该编程领域,编译器手册优先于 C 标准。
Per C99
如果 main.c
和 test.c
都需要调用同一个函数并且需要标记为 inline
,那么我认为必须定义它在 header 中,因为 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?
但是,这可能会导致生成的 object 代码出现各种奇怪的行为。例如,我见过来自 major MCU mfg 的编译器(他们会故意不命名)为 inline
函数生成 object 代码 #included
在给定的翻译单元中 而不是内联它们 。该文件包含在几个地方并包含许多功能,因此这导致整个代码库中整体 ROM 使用量大幅增加,因为链接器也无法删除死代码(请参阅 --gc-sections
for gcc
)和未能提高性能,因为这些函数从未真正内联,即使 技术上 内联的正确使用。
我们对这个特定问题的解决方案是将所有函数转换为宏(这提供了 inline
预期的性能优势),但另一种方法是从声明中删除 inline
并将定义移动到单个 .c
文件。
TL;DR: 如果对 MCU 使用 inline
,1) 查阅您的编译器手册,以及 2) 留意生成的 object 代码.
您可以在 C 中使用 inline
关键字,但如果您使用的是 GNU GCC 编译器,则内联函数也需要是 static
函数。因此,您只能在同一个源文件上使用这些函数。如果你想声明一个你在某个头文件中定义的全局内联函数,并在包含该头文件的源文件上使用它,你可以使用 GNU GCC 的 always_inline
属性,如下所示:
static inline __attribute__((always_inline)) int foo(int a)
{
return a+2;
}
不要忘记在同一头文件中声明内联函数的主体。
继inline
函数。
我想在test.h中声明inline
函数,在main.c中定义它从 test.c.
main.c 和 test.c 都是 #include "test.h"
(代码示例请点击上面的 link)。
这基本上是用户可以使用的某种回调函数 enable/disable。并且只有一个文件应该具有函数 defined.
我知道 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
链接器将负责查找函数定义。
如果函数未在任何编译文件中定义,则
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
。
如果函数 returns void
那么一个不错的技巧是使用这个
#define inlinedFunction(parameters) \
do { \
/* function body here */ \
} while (0)
您应该在宏定义的每一行末尾添加一个连续的反斜杠。
大多数 8 位微控制器代码是用类似于 C89 的语言编写的(通常有扩展,例如内联汇编),并且 inline
不是 官方 的一部分C 到 C99。所以首先要确定你正在编译的标准(如果有的话),如果 inline
是一个扩展(即不是 C99 内联),请查阅你的编译器手册。在该编程领域,编译器手册优先于 C 标准。
Per C99
如果 main.c
和 test.c
都需要调用同一个函数并且需要标记为 inline
,那么我认为必须定义它在 header 中,因为 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?
但是,这可能会导致生成的 object 代码出现各种奇怪的行为。例如,我见过来自 major MCU mfg 的编译器(他们会故意不命名)为 inline
函数生成 object 代码 #included
在给定的翻译单元中 而不是内联它们 。该文件包含在几个地方并包含许多功能,因此这导致整个代码库中整体 ROM 使用量大幅增加,因为链接器也无法删除死代码(请参阅 --gc-sections
for gcc
)和未能提高性能,因为这些函数从未真正内联,即使 技术上 内联的正确使用。
我们对这个特定问题的解决方案是将所有函数转换为宏(这提供了 inline
预期的性能优势),但另一种方法是从声明中删除 inline
并将定义移动到单个 .c
文件。
TL;DR: 如果对 MCU 使用 inline
,1) 查阅您的编译器手册,以及 2) 留意生成的 object 代码.
您可以在 C 中使用 inline
关键字,但如果您使用的是 GNU GCC 编译器,则内联函数也需要是 static
函数。因此,您只能在同一个源文件上使用这些函数。如果你想声明一个你在某个头文件中定义的全局内联函数,并在包含该头文件的源文件上使用它,你可以使用 GNU GCC 的 always_inline
属性,如下所示:
static inline __attribute__((always_inline)) int foo(int a)
{
return a+2;
}
不要忘记在同一头文件中声明内联函数的主体。