存储类&作用域&生命周期&链接属性&inline

总结:
(1)普通(自动)局部变量分配在栈上,作用域为代码块作用域,生命周期是临时,连接属性为无连接。定义时如果未显式初始化则其值随机,变量地址由运行时在栈上分配得到,多次执行时地址不一定相同,函数不能返回该类变量的地址(指针)作为返回值。
(2)静态局部变量分配在数据段/bss段(显式初始化为非0则在数据段,显式初始化为0或未显示初始化则在bss段),作用域为代码块作用域(人为规定的),生命周期为永久(天然的),链接属性为无连接(天然的)。定义时如果未显式初始化则其值为0(天然的),变量地址由运行时环境在加载程序时确定,整个程序运行过程中唯一不变;静态局部变量其实就是作用域为代码块作用域(同时链接属性为无连接)的全局变量。静态局部变量可以改为用全局变量实现(程序中尽量避免用全局变量,因为会破坏结构性)。
(3)静态全局变量/静态函数和普通全局变量/普通函数的唯一差别是:static使全局变量/函数的链接属性由外部链接(整个程序所有文件范围)转为内部链接(当前c文件内)。这是为了解决全局变量/函数的重名问题(C语言没有命名空间namespace的概念,因此在程序中文件变多之后全局变量/函数的重名问题非常严重,将不必要被其他文件引用的全局变量/函数声明为static可以很大程度上改善重名问题,但是仍未彻底解决)。
(4)写程序尽量避免使用全局变量,尤其是非static类型的全局变量。能确定不会被其他文件引用的全局变量一定要static修饰。
(5)注意区分全局变量的定义和声明。一般规律如下:如果定义的同时有初始化则一定会被认为是定义;如果只是定义而没有初始化则有可能被编译器认为是定义,也可能被认为是声明,要具体分析;如果使用extern则肯定会被认为是声明(实际上使用extern也可以有定义,实际上加extern就是明确声明这个变量为外部链接属性)。
(6)全局变量应该定义在c文件中并且在头文件中声明,而不要定义在头文件中(因为如果定义在头文件中,则该头文件被多个c文件包含时该全局变量会重复定义)。
(7)在b.c中引用a.c中定义的全局变量/函数有2种方法:一是在a.h中声明该函数/全局变量,然后在b.c中#include <a.h>;二是在b.c中使用extern显式声明要引用的函数/全局变量。其中第一种方法比较正式。
(8)存储类决定生命周期,作用域决定链接属性
(9)宏和inline函数的链接属性为无连接。

inline总结:
1.什么是inline?
答:一个函数的程序进行代码拓展而不被调用,用相应的函数代码替换函数调用。
2.为什么要用函数内联?
答:为了提高程序执行的效率,内联函数的代码会被直接插入到每个调用函数的地方,从而减少调用函数的开销
3.使用宏定义和使用函数内联有什么区别?
答:
宏定义:
(1)宏定义是通过文本替换来实现的
(2)不用普通函数调用就看起来像函数调用
(3)宏的实现使用的是预处理器,直接用宏代码进行调用,所以就没有参数压栈,生成汇编语言,返回参数等时间花费,所有工作由预处理器完成
(4)但是宏会产生意想不到的边际效应,因为它只进行单纯的文本替换,如果是表达式,展开后的优先级就会跟原来的不一样
(5)预处理器不允许存取私有数据
(6)预处理器对参数不会进行安全检查

函数内联:
(1)inline 对编译器来说是一种请求,而不是命令
(2)对参数进行类型安全检查
(3)可以存取私有数据成员
(4)定义在类中的函数自动成为内联函数
(5)循环和递归不能为内联函数

4.使用函数内联有什么缺点?
(1)任何种类的循环都会被认为太复杂而不被拓展为内联函数
(2)内联只能在定义它的源文件中使用
(3)内联是以代码的膨胀为代价,对于函数体比较短的函数应该采用内联。但是对于函数体比较长的,内联形式的使用反而会降低效率。
(4)类的构造函数和析构函数容易让人误解为使用内联更加有效,但是构造函数和析构函数很可能偷偷隐藏一些行为,所以最好把构造函数和析构函数放在类声明的外面

5.内联具体是怎么实现的?
编译器在它的符号表里放入函数类型和参数(包括函数名字和参数类型及返回值类型),另外,编译器看到内联函数和内联函数的分析没有错时,函数的代码也被放入符号表中,代码是以源程序的形式存放还是以编译过的指令存放取决于编译器。

调用一个内联函数时,编译器首先保证正确,即所有的参数类型必须是正确的或者编译器能够将类型转换为正确类型,并且返回值在目标表达式里应该是正确的类型或者可以改为正确的类型。
假如内联函数是成员函数,对象的地址(this)指针就会被放到合适的位置,这也是预处理器做不到的

6.使用内联有什么要求么?
(1)短函数,对于函数体较长的函数,内联就会降低效率。
(2)如果一个函数是在类声明内定义的,它将自动转换为内联函数
(3)在头文件里,内联函数默认为内部连接—即它是static,并且只能再被包含的编译单元里面看到,因此,只要他们在不相同的编译单元中声明,在内联函数和全局函数之间用相同的名字,在连接时也不会发生冲突
(4)inline 必须与函数定义体放在一起才能使函数成为内联,inline放在声明前不起任何作用,是一种用于实现的关键字,而不是用于声明的关键字。函数的实现与声明不能混为一谈
原文链接:https://blog.csdn.net/chenjieyujiayou/article/details/72416817

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值