跳到主要内容

4.3 函数内联

kf32clang会判断内联某个函数是否可以提升性能,当可以提升性能时会自动对该函数进行内联。这种自动内联通常不会显著增加代码体积,并且你可以使用编译器提示(hints)和选项来影响或控制函数是否被内联。

表4.3 函数内联

内联选项,关键字,或者属性描述
__inline__在函数定义或声明中使用该关键字,可作为提示(hint),告诉编译器优先考虑将该函数内联。然而,对于每次函数调用,编译器仍然会自行决定是否真正进行内联。
__attribute__((always_inline))在函数定义或声明中使用此函数属性,可告诉编译器总是内联该函数,但存在某些例外情况,例如递归函数可能无法内联。该属性会覆盖 -fno-inline-functions 选项的设置。
__attribute__((noinline))在函数定义或声明中使用此函数属性,可告诉编译器不要内联该函数。该属性等效于__declspec(noinline)。
-fno-inline-functions这是一个编译器命令行选项。在编译时指定该选项,可以禁止函数内联。该选项会覆盖 __inline__ 提示。

4.3.1 函数内联示例​

此示例展示了__attribute__((always_inline))和-fno-inline-functions在C99模式下的效果(C文件的默认行为)。将以下代码复制到 file.c。

int bar(int a)
{
a = a * (a + 1);
return a;
}

__attribute__((always_inline)) static int row(int a)
{
a = a * (a + 1);
return a;
}

int foo(int i)
{
i = bar(i);
i = i - 2;
i = bar(i);
i++;
i = row(i);
i++;
return i;
}

在示例代码中,函数 bar 和 row 是相同的,但函数 row 总是被内联。使用以下编译器命令,在 -O2 优化级别下分别编译:第一条命令使用 -fno-inline-functions,第二条命令不使用。

kf32clang --target=kf32r -march=kf32r -S file.c -O2 -o file_no_inline.s -fno-inline-functions
kf32clang --target=kf32r -march=kf32r -S file.c -O2 -o file_inline.s

生成的代码如下所示:

使用 -fno-inline-functions 的编译结果不使用 -fno-inline-functions 的编译结果
foo:
PUSH LR
LJMP bar
SUB R0, R0, #2
LJMP bar
ADD R1, R0, #1
ADD R0, R0, #2
MULS R2, R0, R1
ADD R0, R2, #1
POP LR
JMP LR
foo:
ADD R1, R0, #1
MULS R2, R1, R0
SUB R0, R2, #2
SUB R1, R2, #1
MULS R2, R1, R0
ADD R0, R2, #1
ADD R1, R2, #2
MULS R2, R1, R0
ADD R0, R2, #1
JMP LR

使用 -fno-inline-functions 编译时,编译器不会内联函数 bar。不使用 -fno-inline-functions 编译时,编译器会内联函数 bar。编译器总是内联函数 row,即使它与函数 bar内容相同。