1.内联函数的使用规范

定义:内联函数是指用inline关键字修饰的函数。在类内定义的函数被默认成内联函数。

特点:是编译器可能会将其内联展开,编译时,类似于宏替换,使用函数体替换调用处的函数名,以减少函数调用的开销,无需按通常的函数调用机制调用内联函数。

优点:当函数体比较小的时候,内联该函数可以令目标代码更加高效。

缺点:滥用内联将导致程序变慢,内联有可能使目标代码量增加或减,返取决于被内联的函数的大小。内联较短小的存取函数通常会减少代码量,但内联一个较大的函数(注:如果编译器允许的话)将显著增加代码量。在现代处理器上,由亍更好的利用指令缓存(instruction cache),小巧的代码往往执行更快。

使用inline函数应该遵循以下几点:
(1)内联函数最好不要超过10行;
(2)对于析构函数应慎重对待,析构函数往往比其表面看起来要长,因为有一些隐式成员和基类析构函数(如果有的话)被调用;
(3)递归函数不应该被声明为内联函数。原因是递归调用堆栈的展开并不像循环那么简单,比如递归次数在编译时可能是未知的,大多数编译器都不支持内联递归函数。考察如下代码,一个简单的递归调用:

#include <iostream>
using namespace std;inline void print(int n)
{--n;if(n>0){print(n);}else{for(int i=0;i<5;++i){cout<<"this is inline function:"<<i<<endl;}}
}int main()
{print(10);
}

在VS2017中转到反汇编,其汇编代码为:

int main()
{
002E12B0  push        ebp
002E12B1  mov         ebp,esp
002E12B3  and         esp,0FFFFFFF8h  print(10);
002E12B6  call        print (02E1270h)
}

可见,即使将递归函数print(int n)定义为inline函数,实际上编译器并未将其内联展开,按照正常的函数去调用它。
(4)虚函数不应该被申明为内联函数。因为虚函数的调用较普通函数复杂,需要运行时通过查找虚函数表动态获取虚函数的入口地址,编译器编译阶段是不能确定虚函数的入口地址,故不能将其在编译时静态展开。
(5)如果对析构函数内联,主要原因是在类体重定义,为了方便抑或是其他原因,应对其行为给出文档说明。

2.函数相关规范

2.1函数参数顺序

定义函数时,参数顺序为:输入参数在前,输出参数在后。C/C++函数参数分为输入参数和输出参数两种,有时输入参数也会输出(注:值被修改时)。输入参数一般传值或常数引用(const references),输出参数或输入/输出参数为非常数指针(non-const pointers)。对参数排序时,将所有输入参数置于输出参数之前。不要仅仅因为新添加的参数,就将其置于最后,而应该依然置于输出参数之前。

注意,这一点并不是必须遵循的规则,输入/输出两用参数(通常是类/结构体变量)混在其中,会使得规则难以遵循。

2.2编写功能单一函数

多功能集于一身的函数,很可能使函数的理解、测试、维护等变得困难。 应编写功能单一集中的函数。

2.3编写简短函数

函数的规模尽量限制在80行以内 ,不包括注释和空格行。其次,避免设计多参数函数,不使用的参数从接口中去掉,其目的是为了减小函数接口的复杂度。

2.4尽量编写线程安全函数与可重入函数

2.4.1什么是线程安全函数

线程安全函数是在多线程情况下,可安全地被多个线程并发执行的函数。确保函数线程安全,主要需要考虑的是线程之间的共享变量。属于同一进程的不同线程会共享进程内存空间中的全局区和堆,而私有的线程空间则主要包括栈和寄存器。因此,对于同一进程的不同线程来说,每个线程的局部变量都是私有的,而全局变量、局部静态变量、分配于堆的变量都是共享的。在对这些共享变量进行访问时,如果要保证线程安全,则必须通过加锁的方式。

线程安全函数与线程不安全函数示例:

static int tmp;
//线程不安全函数
void func1(int* x, int* y)
{  tmp=*x;  *x=*y;  *y=tmp;
} //线程安全函数
void func2(int* x, int* y)
{  int tmp;  tmp=*x;  *x=*y;  *y=tmp;
}

func1是线程不安全函数,因为func1在被多线程并发调用时,使用的共享变量tmp可能被其它线程的func1改变,从而导致函数结果的不确定性。解决办法就是给全局变量tmp加锁,或者使用私有局部变量,函数func2()就是这样做的。

2.4.2什么是可重入函数

可重入(reentrant)函数指函数未执行完时重新被调用的函数。例如,函数在响应中断期间,被中断处理函数再次调用。如果函数再次被调用可以安全地进行,那么该函数是可重入函数。相反, 不可重入(non-reentrant)函数再次被调用时,可能导致程序出错甚至崩溃。

一个函数被重入只有两种情况:
(1)多个线程同时执行这个函数;
(2)函数直接或间接地调用自身。

要确保函数可重入,需满足以下几个条件:
(1)不使用(局部)静态或全局的非常量数据;
(2)不返回(局部)静态或全局的非常量数据的地址;
(3)所有依赖的数据均由调用者提供;
(4)不依赖于某个资源的锁;
(5)不调用不可重入函数。

可重入是并发安全的有力保障,在多线程环境下可以安全地调用一个可重入函数。例如下面这个函数是一个可重入函数。

int sqr(int x)
{return x*x
}

2.4.3可重入函数与线程安全函数的区别

(1)关系
可重入函数是线程安全函数的子集,即可重入函数一定是线程安全函数,线程安全函数不一定是可重入函数。关系图如下:

(2)区别
在线程安全函数可以对共享地址空间数据加锁,可重入函数则不能。因为在可重入函数响应中断时,中断处理函数若再次调用该函数时会发生死锁。在多线程环境下,应当做到函数是线程安全的,更进一步,做到可重入 。


参考文献

[1]可重入函数.百度百科
[2]reentrant.百度百科
[3]Google C++编码规范中文版
[4]余甲子,石凡,潘爱民.程序员的自我修养——链接、装载与库[M].北京:机械工业出版社,2009.C1.6众人拾柴火焰高.P27-P28

C++函数使用规范建议相关推荐

  1. Windows客户端C/C++编程规范“建议”——前言

    前言 工作中接触了很多编程规范.其中最有意思的是,公司最近发布了一版C/C++编程规范,然后我看到该规范的最后一段时,有这么一句:"该规范不适用于Windows平台开发".看来这份 ...

  2. [转载]函数编写规范

    一.可重入函数 1)什么是可重入性? 可重入(reentrant)函数可以由多于一个任务并发使用,而不必担心数据错误.相 反, 不可重入(non-reentrant)函数不能由超过一个任务所共享,除非 ...

  3. 来自Mozilla的CSS书写规范建议

    一个来自Mozilla的CSS书写规范建议,希望对大家有帮助 引用内容 //显示属性 display list-style position float clear //自身属性 width heig ...

  4. 【转】Android编码规范建议18条

    转自:http://www.chinaz.com/design/2015/0908/443732.shtml Android编码规范建议18条 适合手机app设计师和android 工程师阅读. 1. ...

  5. 【Python】标识符 ( Python 标识符命名规则 - 强制性 | 内容限定 | 大小写敏感 | 非关键字 | Python 标识符命名规范 - 建议性 | 下划线命名法 | 英文字母全小写 )

    文章目录 一.Python 标识符 1.Python 标识符命名规则 ( 强制性 ) 2.Python 标识符命名规范 ( 建议性 ) 二.代码示例 1.内容限定代码示例 2.大小写敏感 3.非关键字 ...

  6. 呕心沥血集齐史上最全 JavaScript最实用工具函数大全,建议收藏!

    为元素添加on方法 Element.prototype.on = Element.prototype.addEventListener; NodeList.prototype.on = functio ...

  7. 蓝鲸平台MySQL数据库管理规范建议

    蓝鲸平台MySQL数据库管理规范建议 MySQL作为蓝鲸平台存取数据的主要数据库,其稳定性关系到蓝鲸平台的使用体验,而其数据安全性则可能关系到企业IT资产相关信息,在安装和维护蓝鲸平台的过程中应引起足 ...

  8. main函数参数规范

    main函数参数规范 给main函数传递参数,非常容易,而且每个人都有自己的编写方式: 这里介绍一下标准C库的getopt规范,该规范定义了两类参数:短参数和长参数 #include <unis ...

  9. Windows客户端C/C++编程规范“建议”——函数

    1 函数 1.1 代码行数控制在80行及以内 等级:[要求] 说明:每个函数的代码行数控制应该控制在80行以内.如果超过这个限制函数内部逻辑一般可以拆分.如果试图超过这个标准,请列出理由.但理由不包含 ...

最新文章

  1. 三线表是什么?R语言使用table1包绘制(生成)三线表、构建不分层的三线表
  2. js中用到的正则表达式
  3. 【嵌入式】C语言高级编程-变参函数(08)
  4. MySQL5.7.17绿色版安装
  5. windows系统tomcat日志输出至catalina.out配置说明
  6. SystemVerilog声明的位置
  7. php算法台阶,php如何解决青蛙跳台阶的问题(代码)
  8. 全球数字经济白皮书——疫情冲击下的复苏新曙光
  9. [leetcode]5355. T 秒后青蛙的位置
  10. In the beginning, the world was void and without form…
  11. 全国各地网吧网管技术QQ群
  12. 微软2008年7月「最有价值专家」(MVP)当选名单
  13. eggs和egg是什么意思_eggs是什么意思_eggs的翻译_音标_读音_用法_例句_爱词霸在线词典...
  14. 锤子m1l 刷android7.0,锤子M1/M1L收到 Smartisan OS 3.7.0 更新推送
  15. 公众号降权了可以养好嘛,微信公众号降权了多久能恢复
  16. iOS开发篇(二)自定义评分星级条RatingBar
  17. ASO优化:应用市场应该怎么做马甲包?
  18. Java8新特性之Lambda,呦呦呦
  19. CSDN~BLOG目录
  20. linux 格式化 sda,linux – 如何将/ dev / sda挂载并格式化为不同的/ dev / name?

热门文章

  1. CVE-2020-0688 Exchange 远程代码执行分析
  2. Android中ContentProvider组件详解
  3. iOS截取视频预览图,截图方向错误的解决
  4. [wxWidget系列] wxWidget的事件机制
  5. (转载)Hadoop常用SDK系列五 TotalOrderPartitioner
  6. 虚拟环境安装python3
  7. 分享一个蛋疼的俄罗斯方块小游戏
  8. Ubuntu搭建嵌入式开发(交叉编译)环境-转
  9. java GoF 的 23 种设计模式的分类和功能
  10. Xcode误删Images.xcassets文件夹的恢复办法(Assets.xcassets)