关于头文件中的 static inline函数

2023-05-16

原文地址:http://blog.csdn.net/huanghui167/article/details/41346663


关于头文件中的 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函数实体过多的问题它也不存在。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

关于头文件中的 static inline函数 的相关文章

  • 常量引用、非常量引用、临时对象

    转载自 xff1a https www cnblogs com littleant archive 2012 08 01 2618846 html https www cnblogs com BensonLaur p 5234555 htm
  • 字符串string中“\0“与‘\0‘的打印、拼接问题

    1 34 0 34 为字符串长度为0的字符串指针 xff0c 它与 34 34 等价 2 打印 34 0 34 与 39 0 39 相同 xff0c cout输出时都会显示为空 39 0 39 在string的初始化和拼接中size大小的不
  • Direct3D的初始化

    1 获取接口IDirect3D9 的指针 xff0c 该接口用于获取系统中物理硬件设备的信息并创建接口IDirect3DDevice9 xff0c 该接口是一个C 43 43 对象 xff0c 代表了我们用来显示3D图形的物理硬件设备 使用
  • 绘制流水线

    顶点结构与顶点格式 在Direct3D中 xff0c 顶点除了包含空间信息外 xff0c 还可以包含其他的附加属性 xff0c 例如顶点可以有颜色属性 xff0c 也可以有法线属性 xff0c Direct3D赋予了我们自定义顶点格式的自由
  • Direct3D中的绘制

    顶点缓存与索引缓存 一个顶点缓存是一个包含顶点数据的连续内存空间 xff0c 一个索引缓存是一个包含索引数据的连续内存空间 xff0c 之所以使用顶点缓存和索引缓存而非数组来存储数据 xff0c 是因为顶点缓存和索引缓存可以被放置在显存 中
  • 结构体内的指针

    利用 结构体对象 对 结构体内的指针 赋值 include 34 stdafx h 34 include lt string h gt include lt stdlib h gt struct Student char name 从节省空
  • 自制廉价难度低性能较好的锂电充电器(转)

    转载自 xff1a http www geek workshop com thread 53 1 1 html 自制廉价难度低性能较好的锂电充电器 附电压平衡器第一张 电路全图 这张有点模糊 别急 先看大致位置 等一下再分区介绍 这一部份
  • 子类调用父类中的友元函数

    由于友元函数并非类成员 xff0c 因此不能被继承 xff0c 在某种需求下 xff0c 可能希望子类的友元函数能够使用父类中的友元函数 为此可以通过强制类型转换 xff0c 将子类的指针或是引用强转为父类的引用或是指针 xff0c 然后使
  • 判断一个字符是否是十六进制

    判断一个字符是否是十六进制 十六进制 xff08 hexadecimal xff09 是计算机中数据的一种表示方法 xff0c 意思是逢十六进一 十六进制数以16为基数 xff0c 采用的数码是0 1 2 3 4 5 6 7 8 9 A B
  • 库文件、静态库(lib)与动态库(dll)的生成与使用

    静态库 程序编译一般需经预处理 编译 汇编和链接几个步骤 在应用中 xff0c 有一些公共代码是需要反复使用 xff0c 就把这些代码编译为 库 文件 xff1b 在链接步骤中 xff0c 连接器将从库文件取得所需的代码 xff0c 复制到
  • 句柄Handle的含义及使用

    句柄Handle的含义及使用 1 句柄 xff1a 头文件 xff1a winnt h 也可以使用windows h头文件 xff0c 如果winnt h和windows h一起包含时 xff0c 如果先后顺序不当 xff0c 会造成错误
  • SkeyeExPlayer(Windows)开发之接口说明

    SkeyeExPlayer xff08 windows xff09 接口说明如下 xff1a SkeyeExPlayer Open 说明 xff1a 打开一个媒体流或者媒体文件进行播放 xff0c 同时返回一个 player 对象指针 参数
  • 无人机视觉 机器学习 opencv

    最近开始学习机器视觉 xff0c 主要想实现的功能就是无人机的视觉导航 避障 为了实现这个功能 xff0c 涉及到的图像的识别 xff0c 图像的处理 xff0c 通过一张二维的图片来解算出实际物体在现实中的特征描述 xff0c 通过对现实
  • Java中char 转化为int 的两种方法

    今天机试过程中遇到一个问题 xff1a 如何把 char 9 转为 int 9 大家应该知道 xff0c 不能直接转化 xff0c 那样得到是 9 的Ascii 如下面 xff1a public class IntAndCharConver
  • 【代码】给Typecho添加访客信息气泡提醒

    转载请注明出处 xff1a 小锋学长生活大爆炸 xfxuezhang cn 目录 效果如图 设置方法 效果如图 设置方法 1 进入管理后台 xff0c 在 插入代码 处选 自定义增加 xff0c 或者其他可以输入 自定义代码 的地方 xff
  • 【翻译】Mobisys的Student Travel Grants

    我们很自豪地宣布 xff0c MobiSys 2023 将支持学生使用旅行补助金参加会议 学生旅行补助金 该计划的目的是通过为否则无法参加的学生提供旅行费用来鼓励研究生参加会议 资格 xff1a 此补助金的申请人在实际参加 MobiSys
  • 【教程】PyG入门,初步尝试运行第一行GNN代码

    转载请注明出处 xff1a 小锋学长生活大爆炸 xfxuezhang cn Colab Notebook 安装必备的库 Install required packages import os import torch os environ
  • quicker.em在sourceinsight 4中的使用

    quicker em可以在sourceinsight 3 5中很好使用 xff1b 也很方便 xff1b 先多谢大牛 但是 xff0c 将quicker em添加到sourceinsight 4中 xff0c 绑定快捷键 xff0c 根本就
  • 【教程】使用 Captum 解释 GNN 模型预测

    转载请注明出处 xff1a 小锋学长生活大爆炸 xfxuezhang cn Colab Notebook 安装必须的库 xff1a Install required packages import os import torch os en
  • 【教程】使用ChatGPT制作基于Tkinter的桌面时钟

    目录 描述 代码 效果 说明 下载 开源链接 xff1a GitHub 1061700625 Tkinter Desktop Clock 基于Tkinter的桌面时钟小工具 描述 给ChatGPT的描述内容 xff1a python在桌面上

随机推荐