C/C++教程

关于c/c++变量作用域及链接属性的总结

本文主要是介绍关于c/c++变量作用域及链接属性的总结,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

关于c/c++变量作用域及链接属性的总结

作用域

代码块作用域:

位于一对花括号之间所有的语句称之为一个代码块。任何在代码块开始位置声明的标识符都具有代码块作用域,表示它们可以被这个代码块中所有的语句访问。但是,内层嵌套的语句和外层的标识符同名时,内层的那个标识符会覆盖外层的那个同名的标识符

文件作用域:

任何在代码块之外声明的标识符都具有文件作用域,它表示这些标识符从它们的声明之处直到它所在的文件结尾处都是可以访问的,并且我们在函数中定义的函数名也具有文件作用域。要注意的是,在头文件中编写并且通过#include指令包含到其他文件中的声明就好像是它们直接写在那些文件中一样。它们的作用域并不局限于头文件的文件尾。

原型作用域:(所用极少)

原型作用域只适合用于在函数原型中声明的参数名

函数作用域:(所用极少)

函数作用域,它只适合用于语句标签,语句标签用于goto语句

链接属性

当组成一个程序的各个源文件分别被编译之后,所有的目标文件以及那些从一个或多个函数库中的引用的函数链接在一起,形成可执行文件。但是当相同的标识符出现在几个不同的源文件中时,它们是表示同一个实体还是不同的实体?标识符的链接属性决定如何处理在不同文件中出现的标识符。标识符的作用域与它的链接属性有关,但两个属性并不相同;

External(外部):

属于external链接属性的标识符不论声明多少次,位于几个源文件都表示同一个实体;

Internal(内部):

属于internal的链接属性的标识符在同一个源文件当中都指向同一个实体,但是位于不同原文件的多个声明则分属不同的实体;

None(无):

没有链接属性的标识符(none),总是别当作单独的个体,也就是说该标识符的多个声明被当作独立不同的实体;

注意:

  1. 在缺省的情况下,代码块之外声明的标识符都具有external链接属性,包括函数的函数名标识符;
  2. Internal链接属性只在标识符的前面加上static关键字才会有
  3. 其余的都是none链接属性
  4. 标识符的作用域与链接属性有相关之处,但是两者并不相同。作用域指的是某个标识符只有在它的作用域当中才能被访问,或则说其生命周期是从声明开始的地方到所在作用域结束的地方。而,链接属性解决的是当我们碰到相同的标识符出现在不同源文件中的时候定位的是哪一个标识符;
  5. external链接属性的变量定义只能在源文件(.cpp)中定义,不能在头文件(.h)中定义

关键字

关键字extern和static用于在声明中修改标识符的链接属性,如果某个标识符具有external链接属性,加上static则此标识符的链接属性就会变为internal。注意static只对缺省属性为external的声明才有效

extern关键字为一个标识符指定external链接属性,这样我们就可以在其它任何位置访问这个标识符的实体

存储类型

普通内存:

变量的缺省存储类型取决于它的声明位置。凡是在任何代码块之外声明的变量总是存储于静态内存中,也就是不属于堆栈的内存。静态变量创建于程序运行之前,在整个程序的执行期间都存在,他始终都保存原先的值,除非付给他一个不同的值,或则程序结束;

运行时堆栈:

在代码块内部声明的变量的缺省存储类型是是自动的,也就是说它存储在堆栈中,称为自动变量;但是假如我们给在代码块中定义的变量加上static,那么它的存储类型就会变为静态类型,但是它的作用于不变(前面讲过static修改链接属性只对原本的链接属性为external才有用,而代码块中定义的缺省都为internal);

硬件寄存器:

在变量前面加上register,可以用于自动变量的声明,提示他们应该存储于机器的硬件存储器而不是内存中,这类变量称为寄存器变量;但是这种定义不一定会起作用,由编译器来决定

关于存储类型的第二种说法

变量的存储类型

1:auto  自动变量(动态存储)

声明中有auto修饰符时,具有动态存储周期。这种修饰符只能用于函数内部的对象声明。在ANSIC中,默认情况下函数内部都有动态的存储周期,所以不需要用修饰符auto

2:register 寄存器变量(动态存储)

当声明的对象有动态存储周期时,可以使用修饰符register.关键字告诉编译器,所声明对象的访问应该尽快,应该将对象保存在寄存器中,但最终决定由编译器给出

3:extern  外部变量(静态存储)

被声明为extern的函数和对象标识符具有外部链接。可以在程序中任何地方使用这些标识符。外部对象具有静态的存储周期

4:static   静态变量(静态存储)

被声明为static的函数具有内部链接,换句话说,别的翻译单元无法使用所声明的函数标识符来访问函数

头文件(.h)和源文件(.cpp)详解

声明和定义(实现)不一样

在c语言中定义就是把一个符号完整的描述出来:它是变量还是函数,返回什么类型,需要什么参数等等;而声明则只是声明这个符号的存在,即告诉编译器这个符号实在其它文件文件中定义的。定义的时候我们需要按照c的语法完整的定义一个符号,而声明的时候就只需要写出这个符号的原型了;

何为头文件:

头文件实际上就是我们存放声明语句的地方

何为源文件:

源文件其实就是存放我们定义(实现)代码的地方

头文件和源文件的关系

编译器将源文件编译成目标文件,目标文件就是我们的编译单元。一个程序可以由一个编译单元组成,也可以由多个编译单元组成。一个函数不能放到两个编译单元里面,但两个函数或以上就可以分别放在一个单元里面。那么就是一个源文件对应一个目标文件,然后通过链接器组成一个.exe,也就是程序了。

在c++中,使用函数或则变量之前必须要进行声明。那么如果一个源文件要用到另一个源文件定义的函数,只需要在这个源文件中写上它的函数声明就可以了,其余工作由链接器来完成。但是但多个文件都需要使用同一个函数时,那么就要在多份源文件中进行声明,而且如果需要修改这个函数时就必须逐个修改每个源文件。

头文件(.h)就是为了解决这个问题而诞生,它包含了这些公共的函数定义,而且如果需要修改,也只修改头文件的内容即可。

对于将实现放在头文件中的几点考虑:

  1. 会暴露我们的实现细节
  2. 头文件被包含到不同的源文件中,会导致链接冲突。
    1. 比如我们前面所讲的关于定义一个external链接属性的变量,假如我们将定义放在头文件中就会出错,因为external链接属性的变量在整个程序中只有一份。但是头文件却有可能会在多个地方引用,并且头文件还只是简单的替换作用,相当于我们在多个地方定义了一个相同的external链接属性的变量,而者时编译器所无法接受的
    2. 又比如我们将函数的实现写在头文件中,假如头文件在两个地方被包含,那么就相当于有两份此函数的实现,这时链接器就会发生冲突,因为它不确定具体使用那个函数副本

3.头文件被包含到不同的源文件中,会导致有多份实现被编译出来,增大可执行体的体积

这篇关于关于c/c++变量作用域及链接属性的总结的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!