ARM嵌入式编程优化之内联函数(inline)

news/2024/5/20 3:49:56 标签: arm开发, c语言, 嵌入式编译器, 内联函数

内联函数的本质是以空间换时间:增加了代码量,但减少了函数调用时带来的性能损耗。默认情况下,编译器会自己决定是否将一个函数内联。在编译优化时,默认情况下编译器会根据时间对性能进行优化。如果编译器决定内联一个函数,它会确保避免大量的代码增长。当使用-Oz或-Os等编译优化选项来限制代码大小时,编译器对内联做出智能的判断,并旨在将代码量保持在最小。

如果将函数内联可以提高代码性能,Arm嵌入式编译器会自动将函数内联化,这种内联不会显著提高代码量,此外用户也可以用编译选项或者关键词来控制是否将一个函数内联。

Table 1. 函数内联
内联选项、关键字或属性描述
__inline__在函数定义或声明中指定此关键字,以提示编译器支持内联函数。然而,对于每个函数调用,仍然是由编译器来决定是否将函数内联。这个关键字相当于__inline。
__attribute__((always_inline))在函数定义或声明中指定此函数属性,以告诉编译器始终内联此函数,除了递归函数等某些例外情况。此属性将会覆盖-fno-inline-functions选项。
__attribute__((noinline))在函数定义或声明中指定此函数属性,以告诉编译器不要内联函数。这个属性相当于 __declspec(noinline).
-fno-inline-functions这是一个编译器命令行选项。将此选项指定给编译器以禁用内联。此选项覆盖__inline__关键字的功能。
  • 在大多数情况下,是否将函数内联的决定权最好留给编译器。使用 __inline__ 或者 inline 关键字修饰函数,只是向编译器暗示该函数应该内联,但最终的决定权仍在编译器。除非使用__attribute__((always_inline)),它会强制编译器将该函数内联。
  •  c++和C99提供了内联语言关键字。此内联语言关键字的效果与使用内联编译器关键字的效果相同。但是,C99模式下的效果与c++或其他不遵循C99标准的C中的效果不同。
  • 函数内联通常发生在更高的优化级别,例如-O2,除非特别指定了__attribute__((always_inline))。

c源代码的默认语义规则遵循C99规则。当建议将函数内联时,对于内联,编译器希望找到不使用内联的函数的等效实现。当编译器决定不内联时,它使用这个等价的实现。如果编译器找不到等效的实现,则会失败并显示以下错误 :

"Error: L6218E: Undefined symbol <symbol> (referred from <file>)"

为了避免这个问题,有几个办法:

  • 提供函数的等效实现。
  • 将inline或__inline__关键字更改为static inline。
  • 删除inline或__inline__关键字,因为它只是作为一个建议。
  • 使用-std=gnu90选项,使用GNU C90方言编译程序。

下面将演示__attribute__((always_inline)) 和-fno-inline-functions 对编译带来的影响:

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是一样的函数,只不过 使用 __attribute__((always_inline))来修饰了row函数,接下来使用如下两条指令对该源码进行编译:

armclang --target=arm-arm-none-eabi -march=armv8-a -S file.c -O2 -o file_with_inline.s

armclang --target=arm-arm-none-eabi -march=armv8-a -S file.c -O2 -o file_no_inline.s -fno-inline-functions

程序1- 使用-fno-inline-functions的编译结果:

foo:                                    @ @foo
        .fnstart
@ BB#0:
        .save   {r11, lr}
        push    {r11, lr}
        bl      bar
        sub     r0, r0, #2
        bl      bar
        add     r1, r0, #1
        add     r0, r0, #2
        mul     r0, r0, r1
        add     r0, r0, #1
        pop     {r11, pc}
.Lfunc_end0:
        .size   foo, .Lfunc_end0-foo
        .cantunwind
        .fnend

程序2-不使用-fno-inline-functions的编译结果:

foo:                                    @ @foo
        .fnstart
@ BB#0:
        add     r1, r0, #1
        mul     r0, r1, r0
        sub     r1, r0, #2
        sub     r0, r0, #1
        mul     r0, r0, r1
        add     r1, r0, #1
        add     r0, r0, #2
        mul     r0, r0, r1
        add     r0, r0, #1
        bx      lr
.Lfunc_end0:
        .size   foo, .Lfunc_end0-foo
        .cantunwind
        .fnend

从程序1汇编代码中可以看出, __attribute__((always_inline))属性将会覆盖-fno-inline-functions选项,即使在命令行中使用了-fno-inline-functions,来告诉编译器不要内联函数,但编译器仍把row函数内联化了。

从程序2汇编代码中可以看出,就算没有使用inline关键词来修饰函数,编译器会自动判断,将bar函数内联。

参考链接:

Inlining functions


http://www.niftyadmin.cn/n/349713.html

相关文章

Windows 10沙箱安全隔离的虚拟环境保护你的计算机

Windows 10的沙箱&#xff08;Windows Sandbox&#xff09;是一项先进的虚拟化技术&#xff0c;它提供了一个隔离的运行环境&#xff0c;可以在其中安全地运行不受信任的应用程序或文件&#xff0c;同时不会对主机操作系统和数据造成任何影响。沙箱为用户提供了一个安全的测试和…

05 常用类1

枚举类的作用 作用:定义类型安全的且对象数量固定的类,不能被继承 语法: public enum 枚举类名{ 常量对象A,常量对象B,常量对象C; }示例: public enum ClothTypeEnum { // 描述服装的类型 // 常量:ClothTypeEnum类型的常量对象 MEN,WOMEN,NEUTRAL;// 枚举类的普通…

程序员:面试造火箭,入职拧螺丝?太难了···

刚开始工作的时候&#xff0c;我也想不通这个问题&#xff0c;甚至很鄙视这种现象。后面当了面试官&#xff0c;做到了公司中层管理&#xff0c;也会站在公司以及行业角度去重新思考这个问题。 为什么这种现象会越来越普遍呢&#xff1f;尤其在 IT 行业愈加明显。 面试看的是…

基于java的竞赛预约管理信息系统的设计与实现

背景 本系统提供给管理员对首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;项目分类管理&#xff0c;竞赛项目管理&#xff0c;赛事预约管理&#xff0c;系统管理等诸多功能进行管理。本系统对于用户输入的任何信息都进行了一定的验证&#xff0c;为管理员操作提高…

B站动态自检方法1 bilibili应用自检

文章目录 相关地址注意事项主要流程一、手机和电脑连接同一段wif&#xff0c;配置代理&#xff1a;iP&#xff0c;端口&#xff1a;88991、查看IP2、电脑设置代理 二、手机配置代理&#xff0c;其中IP:192.188.0.100&#xff0c;端口&#xff1a;8899三、安装证书四、启动动态自…

领导力 DNA - 用责任心打造核心竞争力、 不只负责、更要当责

一、用责任心打造核心竞争力、 不只负责、更要当责; 1.1 负责: 怎样成为 组织不可或缺的人才? 不可或缺 -> 个人核心竞争力 -> 用什么打造核心竞争力? -> 责任心 责任心对于职业发展的核心作用 改变思维模式、提高责任意识 摒弃拖延…

代码随想录算法训练营第十三天 | 239. 滑动窗口最大值,347.前 K 个高频元素,总结

代码随想录算法训练营第十三天 | 239. 滑动窗口最大值&#xff0c;347.前 K 个高频元素&#xff0c;总结 1.1 239. 滑动窗口最大值 思路&#xff1a; 单调队列的经典题目&#xff0c;保证队列里单调递减或递增的原则窗口是移动的&#xff0c;大顶堆每次只能弹出最大值&#…

MySQL之触发器相关操作

1. 概念 触发器&#xff0c;就是⼀种特殊的存储过程。触发器和存储过程⼀样是⼀个能够完成特定功能、存储 在数据库服务器上的SQL⽚段&#xff0c;但是触发器⽆需调⽤&#xff0c;当对数据表中的数据执⾏DML操作时 ⾃动触发这个SQL⽚段的执⾏&#xff0c;⽆需⼿动调⽤。 在MyS…