一般来说加上static表示函数是文件作用域,有的时候单独使用inline编译器会优化,没有编译成内联函数,而是变成普通函数编译,所以必须在前面加上static,放在头文件中可以被外部文件访问.
 
关于头文件中的 static inline函数
    头文件中常见static inline函数,于是思考有可能遇到的问题,如头文件经常会被包含会不会产生很多副本?网上说法不一。于是自己验证。经过arm-none-eabi-gcc下测试后得出结论。
 
    inline 关键字实际上仅是建议内联并不强制内联,gcc中O0优化时是不内联的,即使是O2以上,如果该函数被作为函数指针赋值,那么他也不会内联,也必须产生函数实体,以获得该函数地址。经测试c文件中的仅inline函数即使Os优化也不内联,因为没有static,编译认他是全局的,因此像普通函数一样编译了,本c文件也一样通过 bl inline_func 这样的方式调用,不像网上别人说的,本c会内联,其他c文件则通过bl inline_func 方式。加入static 后则内联了。(Os优化等级测试)
    所以在头文件中用inline时务必加入static,否则当inline不内联时就和普通函数在头文件中定义一样,当多个c文件包含时就会重定义。所以加入static代码健壮性高,如果都内联了实际效果上是一样的。(gcc下验证过O0级别includes.h中仅定义inline的函数,编译失败,Os编译成功)
 
为什么要在头文件中定义函数呢?
虽然知道了头文件中用inline函数时要加入static,但是为什么要在头文件中定义函数呢?
一些简单的封装接口函数,如 open() { vfs_open() } 仅仅是为了封装一个接口,我们不希望耗费一次函数调用的时间,解决方法一是宏,但是作为接口,宏不够清晰。那选择inline,但是如果在c文件中写
main.c
inline void open(void)
{
    vfs_open();
头文件加声明,外部要使用则不会内联的,因为编译器有个原则,以c文件为单位进行逐个编译obj,每个c文件的编译是独立的,该c文件用到的外部函数都在编译时预留一个符号,只有等到所有obj生成后链接时才给这些符号地址(链接脚本决定地址),所以其他c文件编译时只会看到这个函数的声明而无法知道她的实体,就会像普通函数一样通过bl 一个函数地址,等链接的时候再填入该地址了,他做不到内联展开。
所以要内联则必须在每个用到它的c文件体现实体,那就只有在头文件了,所以会把这类希望全局使用又希望增加效率的函数实现在头文件中static inline
 
static inline 的坏处
    因为inline 是C99才有的关键字,C89没有,有部分编译器不支持,或者部分支持,如支持__inline 或 __inline__等,所以我们一般会用一个宏定义inline 如:
#define INLINE    static inline
不支持inline时:
#define INLINE    static
    但是这样如果编译器不支持inline 即意味着之前 static inline的函数全部被修改为 static,在头文件中写static会有什么后果呢?
经过测试果然和我们想的一样,每个c文件包含了该头文件后全部都有了该函数副本。这无疑增大了很多代码量。比如在include.h
这样的大头文件,几乎每个c文件我们都会包含他,相当于每一C文件都会加入一个 static void func(void){...}  实体。如果是函数宏则不会有这种问题,函数宏是没有实际代码的,没调用他时代码不存在。这就是头文件中用static inline 函数的坏处。但是可以通过优化解决,经过测试,O0优化下在头文件中定义static 函数包含该头文件的三个c文件的确都有了该函数,但是在Os优化下则只有调用了该函数的C文件才有实体。这是由编译器对static函数的特性决定的。总之他的法则和我们想的一致,就是头文件仅仅是单纯的展开,而每个C独立编译,不会因为知道其他个C文件定义了该函数,这个c文件就把他当外部bl了。
 
 
 
关于c文件中的static函数
static函数除了文件内使用这个功能外,在优化上也有作用,static定义后如果该文件没有函数调用他,那么他意味着没有用,其他文件不可能调用,所以开优化就被优化掉了(已验证),无优化时则还在。这点一定要注意中断函数最好不要写static,中断函数如果没有中断服务函数的,即没有被调用,static可能被优化,当然也不一定,因为没有中间服务函数的独立中断服务函数必须在链接脚本体现,可能需要再链接脚本上加入KEEP参数应该就没问题。
 
这里排除非gcc编译器,如code worrior编译器则不同,code worrior是定制型的,通过识别main函数,因此他有主函数枝干可以判断哪些函数被调用,哪些是无用的,但是gcc不同,没有所谓的main,所以三个c文件如果没有static的函数,即使开优化也都会编译出来,他并不知道哪些函数有用,哪些函数无用。而static后他就一定知道他没被调用即无用,所以可以优化掉。
 
以上均指arm-none-eabi-gcc环境下测试的结论,其他编译器有些不同。但是c语言的编译规则还是以gcc为标准,即使其他编译器有些不同我们平时编程时还是以这个为标准。
在codeworrior 编译器上测试,即使0优化依然会把inline内联,有main函数,没有被主干调用的都是无用函数全部被标记UNUSED,不编译,因此上面讨论的当不支持inline时static函数实体过多的问题它也不存在。

c里面的static inline函数的更多相关文章

  1. PHP---------PHP函数里面的static静态变量

    工作一年了,一年里很少用到static这个关键词,不管是类里面还是方法里面基本都没怎么用过.平时看到类里面有这个都没什么好奇的,今天在函数里面看到了这个,就去百度了一下. <?phpfuncti ...

  2. C Static Inline函数

    Inline函数 程序执行时,处理器从Memory中读取代码执行.当程序中调用一个函数时,程序跳到存储器中保存函数的位置开始读取代码执行,执行完后再返回. 为了提高速度,C定义了inline函数,告诉 ...

  3. 对php和java里面的static函数和static的一些理解

    static function: "static方法就是没有this的方法.在static方法里面不可以调用非静态方法,反过来是可以的.并且可以在没有创建任何对象的前提下,仅仅通过类名来调用 ...

  4. STM32F4库函数里面的RCC_DeInit(void)函数分析

    void RCC_DeInit(void) { /*Set HSION bit,内部高速时钟使能HSI振荡器打开*/ RCC->CR |=(uint32_t)0x00000001; /*Rese ...

  5. 内联函数:static inline 和 extern inline 的含义

    引入内联函数的目的是为了解决程序中函数调用的效率问题. 函数是一种更高级的抽象.它的引入使得编程者只关心函数的功能和使用方法,而不必关心函数功能的具体实现:函数的引入可以减少程序的目标代码,实现程序代 ...

  6. java里面的public static void main(String[] args)

    package com.java_1; public class Hello { public static void main(String[] args){ System.out.println( ...

  7. 学习hash_map从而了解如何写stl里面的hash函数和equal或者compare函数

    ---恢复内容开始--- 看到同事用unordered_map了所以找个帖子学习学习 http://blog.sina.com.cn/s/blog_4c98b9600100audq.html (一)为 ...

  8. c++复习基础要点02 虚函数与模板 与static inline是否共存

    1.      虚函数能否定义为模板函数 当一个类有虚函数时,它一定有一个虚表,用来纪录每个虚函数的实际地址.这也就是说这个虚表的大小是在编译期就确定了的.有多少个虚函数,虚表就纪录几个.       ...

  9. 函数的上下文就是函数里面的this是谁

    规律1:函数用圆括号调用,函数的上下文是window对象 比如小题目: function fun(){ var a = 888; alert(this.a); //实际上访问的是window.a } ...

随机推荐

  1. Hailstone冰雹序列问题

    在复习数据结构,课程中提到Hailstone冰雹序列问题,问题如下 代码如下: public List<int> Hailstone(int n) { List<int> li ...

  2. 田螺便利店—opencv3.4.5与vs2015配置并测试

    参考博客:https://blog.csdn.net/sinat_39061823/article/details/80723096 遇到的问题:由于找不到 opencv_world345d.dll, ...

  3. vue day8 table page

    @{ ViewBag.Title = "Home Page"; Layout = null; } <!DOCTYPE html> <html> <he ...

  4. javaee设计模型简介

    (一)五种模式 1.单例模式 在某些情况下,有些对象只需要一个就可以了,即每个类只需要一个实例.例如,一台计算机上的可以连接多台打印机,但是该计算机上的打印程序只能有一个,这里就可以通过单例模式来避免 ...

  5. 高通平台获取secure boot,串号等状态

    adb shell下 运行./system/bin/r address 其中address对应各个flag参数的地址,具体如下: 无法打开/dev/mem节点(没有该节点),这时只需在内核配置中选上C ...

  6. Mysql主外键

    主键  primary   key 创建表时直接加上主键: create table student1(id int primary key, name varchar(20), age int, g ...

  7. Git学习之第一次使用PR

    发起PR的流程 1.Fork想要pr的项目,在自己的仓库里建立一个相同的项目. 2.Clone我们Fork的项目,在本地建立一个项目,方便修改. 3.将修改后的本地项目上传到github上. 4.向原 ...

  8. java基础(三):反射、反序列化破解单列模式和解决方式

    单例模式指的是一个类只有一个对象,通过一些措施达到达到这个目的.但是反射和反序列化可以获得多个不同的对象. 先简单的认识一下单例模式 一:单例模式 通过私有构造器,声明一个该类的静态对象成员,提供一个 ...

  9. R并行计算

    # 参考文献: https://cosx.org/2016/09/r-and-parallel-computinghttps://blog.csdn.net/sinat_26917383/articl ...

  10. redis 设置分布式锁要避免死锁

    1. jedis 中 setnx key value 虽然可以处理同步问题 (setnx 有返回值 1是key不存在把它设置进去,0是key已经存在了)但是 setnx设置完后 程序的下一步 有可能挂 ...