嵌入式C代码属性怎么定义?( 四 )

如果我们在main.c 中定义了f()函数,那么main 函数调用f()会调用薪定义的函数,否则调用__f()函数 。
8. 属性声明:noinline 和 always_inline8.1 什么是内联函数说起内联函数,就不得不说起函数调用开销 。一个函数在执行过程中,如果要调用其他函数,则一般会执行以下过程:

  • 保存当前函数现场
  • 跳到调用函数执行
  • 恢复当前函数现场
  • 继续执行当前函数
对于一些短小精悍,并且调用频繁的函数,调用开销大,这个时候我们可以将函数声明为内联函数 。编译器遇到内联函数会想宏一样将内联函数之间在调用处展开,这样做就减少了函数调用的开销 。
8.2 内联函数与宏与宏相比,内联函数有以下优势:
  • 参数类型检查:内联函数本质上还是一个函数,在编译过程中编译器会对齐进行参数检查,而宏不具备这个特性 。
  • 便于调试:函数支持的调试功能有断点、单步等 。
  • 返回值:内联函数有返回值 。这个优势是相对于ANSI C 说的 。因为现在的宏也有返回值和类型了,如使用语句表达式定义的宏 。
  • 接口封装:有些内联函数可以用来封装一个接口,而宏不具备这个特性 。
8.3 编译器对内联函数的处理我们虽然可以通过inline 关键字将一个函数声明为一个内联函数,但是编译器不一定会对这个函数内联展开 。编译器也要根据实际情况进行评估,权衡展开和不展开的利弊,并最终决定要不要展开 。
内联函数并不是完美的,也有一些缺点 。内联函数会增大程序的体积 。
一般而言判断一个内联函数是否展开,从程序员的角度主要从以下几点出发:
  • 函数体积小
  • 函数体内无指针赋值、递归、循环语句等
  • 调用频繁
当我们认为一个函数体积小、而且被大量调用,应做内联展开时,就可以使用static inline 关键字修饰它,但是编译器不一定会内联展开 。如果想明确告诉编译器一定要展开,或者不展开就可以使用 noinline 和 always_inline 对函数的属性做一个声明 。
8.4 内联函数为什么定义在头文件中?在Linux 内核中,你会看到大量的内联函数被定义在头文件中,而且常常使用static关键字修饰 。
为什么定义在头文件中呢?因为它是一个内联函数,可以像宏一样使用,在任何想使用内联函数的源文件中,都不必亲自在定义一遍,直接包含这个头文件即可 。
为什么还要用static 修饰呢?因为使用inline关键字定义的内联函数,编译器不一定会内联展开,那么当一个工程中多个头文件包含这个内联函数的定义时,编译时就可能报重复定义的错误 。使用satic 关键字修饰,则可以限定这个函数的作用域在各自的源文件内,避免重复定义的发生 。
9. 总结本文主要介绍了 GNU C 的扩展语法 __attributr__ 关键字,并对其中常用的属性声明做了详细的介绍:
  • section
  • packed
  • aligned
  • format
  • alias
  • weak
  • noinline
  • always_inline
 
 
原文链接:
https://mp.weixin.qq.com/s/i8weiCtfuCaewsTqUWl9Jw
转载自:嵌入式微处理器
原文链接:嵌入式C代码属性怎么定义?

【嵌入式C代码属性怎么定义?】


推荐阅读