1,本节课学习 C++ 中才引入的新的概念,内联函数;

2,常量与宏回顾:

1,C++ 中的 const 常量可以替代宏常数定义,如:

1,const int A = 3; <==> #define A 3

2,C++ 中如果要使用宏常数,则可以用 const 常数代替;

2,C++ 中是否有解决方案替代宏代码片段呢?

1,为了替换宏代码块,内联函数的概念被提出;

3,内联函数用法:

1,C++ 中推荐使用内联函数替代宏代码片段;

1,宏代码块看上去像函数但实际不是函数,因此其使用常带有副作用;

2,消除这样的副作用需要函数,但是函数的调用有入栈返回等开销,这一点宏代码块没有;

3,综合两者有点,避免两者缺点,内联函数被提出来;

2,C++ 中使用 inline 关键字声明内联函数;

 inline int func(int a, int b)
{
return a < b ? a : b;
}

1,内联函数在表现形式上和普通函数一样,但是它会被编译器进行优化,编译器直接将内联函数的函数体进行扩展,这个扩展由编译器直接将生成的代码进行扩展,扩展到调用这个内联函数的地方,由编译器进行,所以会进行编译器检查等一些列工作;

2,inline 可以将一个函数声明为内联函数,但是这种声明是对编译器的一种请求,请求编译器将这个函数进行内联编译,所以编译器可以拒绝内联请求;

3,内联函数声明时 inline 关键字必须和函数定义结合在一起,否则编译器会直接忽略内敛请求;

4,内联函数特点:

1,C++ 编译器可以将一个函数进行内联编译;

2,被 C++ 编译器内联编译的函数叫做内联函数;

1,内联函数在 C++ 中的地位是用来替换 C 中的宏代码块;

3,C++ 编译器直接将函数体插入函数调用的地方;

4,内联函数没有普通函数调用时的额外开销(压栈,跳转,返回);

1,C++ 编译器不一定满足函数的内敛请求;

1,此时内联函数变为普通函数,行为同普通函数;

5,内联函数初探编程实验:

1,main.cpp 文件:

 #include <stdio.h>

 /* 宏代码块 */
#define FUNC(a, b) ((a) < (b) ? (a) : (b)) /* 声明一个内联函数 */
inline int func(int a, int b)
{
return a < b ? a : b;
} int main(int argc, char *argv[])
{
int a = ;
int b = ;
int c = FUNC(++a, b); // ==> int c = ((++a) < (b) ? (++a) : (b)); 这里 a 加了两次; // int c = func(++a, b); printf("a = %d\n", a);
printf("b = %d\n", b);
printf("c = %d\n", c); return ;
}

    1,宏调用结果:

      a =  b =  c = c

    2,函数调用结果:

      a =  b =  c =

    3,VC 工程属性优化 inline 默认:

    4,VC 工程属性优化 inline 内联:

    5,Eclipse 工程 g++ 编译 inline 内联:

2,结论:

  1,内联函数函数请求有可能被拒绝;

  2,内联函数是存在的,可以替换宏代码块;

6,内联函数特征:

1,内联函数具有普通函数的特征(参数检查,返回类型等);

1,类型更加安全;

2,C++ 提供各种方式让大家摒弃 C 中不好的一些特性,内联函数就是其中之一;

2,函数的内联请求可能被编译器拒绝;

1,可以通过配置的方式让编译器支持内联函数的请求;

3,函数被内联编译后,函数体直接扩展到调用的地方;

1,如果内联成功,其效率上可以和宏代码块媲美,且其在类型上比宏代码块安全很多,因此在 C++ 编程中,首选内联函数;

2,宏代码片段由预处理器处理,进行简单的文本替换,没有任何编译过程,因此可能出现副作用;

7,现代 C++ 编译器对内联函数的行为:

1,现代 C++ 编译器能够进行编译优化,一些函数即使没有 inline 声明,也可能被内联编译;

1,内联函数可能被拒绝是因为 C++ 诞生年代相对于现在比较早,当时编译 技术未有达到现在先进的技术,因此对于一些复杂的内联函数,C++ 编译器没有能力将函数体直接扩展到调用的地方,所以 inline 关键字在当时设计成了对编译器的请求;

2,一些现代 C++ 编译器提供了扩展语法,能够对函数进行强制内联,如:

1,g++:__attribute__((always_inline)) 属性;

1,不是标准 C++ 属性;

2,MAVC:__forceinline;

8,内联函数深度示例编程实验:

1,main.cpp 文件:

 #include <stdio.h>

 __forceinline
// __attribute__((always_inline))
// inline
int add_inline(int n); int main(int argc, char *argv[])
{
int r = add_inline(); // 关注此行; printf(" r = %d\n", r); return ;
} inline int add_inline(int n)
{
int ret = ; for(int i=; i<n; i++)
{
ret += i;
} return ret;
}

1,inline 时:

1,VC 默认的,不内联,设置后,就内联;

2,g++ 默认的,不内联,设置后,就内联;

3,__forceinline,内联:

1,对于 VC++ 编译器,forceinline 和 inline 功能几乎是一模一样,只不过后者是标准 C++ 支持的,可移植性更好;

4,__attribute__((always_inline)):

1,对于 g++ 编译器,内联;

9,注意事项:

1,C++ 中 inline 内联编译的限制:

1,不能存在任何形式的循环语句;

1,这个限制现在也没有了;

2,不能存在过多的条件判断语句;

3,函数体不能过于庞大;

4,不能对函数进行取址操作;

5,函数内联声明必须在调用语句之前;

2,总的来说就是函数体不能过于复杂,这个复杂没有界定,对于现在 C++ 编译器,只要函数不是太夸张,几乎都可以满足请求;

10,小结:

1,C++ 中可以通过 inline 声明内联函数;

2,编译器直接将内联函数体扩展到函数调用的地方;

3,inline 只是一种请求,编译器不一定允许这种请求;

4,内联函数省去了函数调用栈时压栈,跳转和返回的开销;

C++中的内联函数分析的更多相关文章

  1. JAVA中的内联函数

    在说内联函数之前,先说说函数的调用过程. 调用某个函数实际上将程序执行顺序转移到该函数所存放在内存中某个地址,将函数的程序内容执行完后,再返回到 转去执行该函数前的地方.这种转移操作要求在转去前要保护 ...

  2. 《挑战30天C++入门极限》新手入门:关于C++中的内联函数(inline)

        新手入门:关于C++中的内联函数(inline) 在c++中,为了解决一些频繁调用的小函数大量消耗栈空间或者是叫栈内存的问题,特别的引入了inline修饰符,表示为内联函数. 可能说到这里,很 ...

  3. C语言中宏定义与C++中的内联函数

    一,宏定义:在预处理的时候把宏定义的内容替换到代码中,正常编译. 1,无参数宏定义和有参数宏定义 (1)宏定义不能加分号,比如:#define  PI 3.24;错的,#define  PI 3.24 ...

  4. C++中的内联函数和C中的宏定义的区别

    在C++中内联函数: 内联函数即是在函数的声明和和定义前面加上“inline”关键字,内联函数和常规函数一样,都是按照值来传递参数的,如果参数为表达式,如4.5+7.5,则函数将传递表达式的值(这里为 ...

  5. C++解析(5):内联函数分析

    0.目录 1.常量与宏回顾 2.内联函数 3.内联函数深度探析 4.注意事项 5.小结 1.常量与宏回顾 C++中的const常量可以替代宏常数定义,如: const int A = 3; <- ...

  6. 07 c++中的内联函数inline

    文章链接: 问题描述:类中成员函数缺省默认是内联的,如果在类定义时就在类内给出函数定义,那当然最好.如果在类中未给出成员函数定义,而又想内联该函数的话,那在类外要加上 inline,否则就认为不是内联 ...

  7. 谈谈 OC 中的内联函数

    内联函数 即在编译的时候将函数体替换函数调用.从而不须要将parameter,returnaddress进行push/pop stack的操作, 从而加速app的执行.然而,会添加二进制文件的大小. ...

  8. C++中的内联函数

    (1)定义.函数声明和定义时,在返回值类型前加inline关键字. (2)作用.避免调用时的额外开销. (3)使用情况.函数体很小,且频繁调用. (4)本质.通过牺牲代码段空间,来提高程序运行的时间效 ...

  9. (inline)内联函数在IOS开发中的使用

    今天在阅读YYKit源码(https://github.com/ibireme/YYKit.git)时发现在YYKitMacro.h组件中大量使用的内联函数,例如此文件中的一个函数 static in ...

随机推荐

  1. jQuery easyUI 使用 datagrid 表格

    获取后台数据依旧是使用一般处理程序(ashx) ,分页上添加一个函数(pagerFilter(data)) 前端代码: <%@ Page Language="C#" Auto ...

  2. Java解析Groovy和Shell的代码

    一.使用场景 在整个系统中,通用型的代码基本没什么变化,需要变动的仅仅是业务相关的代码.那么我们就会把一些业务代码简单编码一下放在数据库中.通过数据库的配置,可以直接从数据库中查找出来编码处理一下,来 ...

  3. [转载]Linux上使用ssl进行端口转发

    原文地址:Linux上使用ssl进行端口转发 作者:呼延十 背景介绍 作为一个后端程序员,经常要和别人联调接口,每当这时,总是被公司的各种,dev,qa,pre,prod环境搞得头疼,,,我真的只是想 ...

  4. foreach与正常for循环效率对比

    foreach foreach编译成字节码之后,使用的是迭代器实现的. foreach特点: 无须获取容器大小 需要创建额外的迭代器变量 遍历期间得到的是对象,没有索引位置信息,因此不能进行赋值操作. ...

  5. Sass-注释

    注释对于一名程序员来说,是极其重要,良好的注释能帮助自己或者别人阅读源码.在 Sass 中注释有两种方式,我暂且将其命名为: 1.类似 CSS 的注释方式,使用 ”/* ”开头,结属使用 ”*/ ”2 ...

  6. center os 下redis安装以及基本使用

    解压并进入其目录 make cd src make install 默认情况,Redis不是在后台运行,我们需要把redis放在后台运行 vim /usr/local/redis/etc/redis. ...

  7. 商城分类导航实现 (css)

    代码实例:demo.html <!DOCTYPE html> <html lang="en"> <head> <meta charset= ...

  8. HTML5 canvas绘制图片

    demo.js window.onload=function() { createcanvas(); drawImage(); } function createcanvas() { var CANV ...

  9. websock(AMQ)通信-前端

    服务端和客户端之间的通信 前端开发经常会依赖后端,那么如果后端服务器还没做好推送服务器,那么前端该如何呢.最简单的就是自己模拟一个服务器,用node来搭建,这边只简单介绍搭建的过程 node搭建服务器 ...

  10. 前端BFC布局学习

    BFC,全称为(Block formatting context).按照我的理解是我们在某一条件下会触发BFC布局,会产生一定的效果. Block Formatting Contexts翻译为:块级元 ...