变量作用域
目录:
- 变量作用域
- 概念
- typedef声明
- 局部变量
- 全局变量
- 静态变量
- c++存储类
- auto 自动存储类
- static 静态存储
- register 注册存储类
- extern 外部存储类
- 多文件编程
- 多文件编程概念
- 步骤
- include <> 和 #include ""的区别
- 防止头文件重复包含
- 使用宏定义避免重复引入
- 使用#pragma once避免重复引
- 用_Pragma操作符
概念
C++ 中的一个 变量 或 常量 在程序中都有一定的作用范围,称之为作用域。
变量定义
作用:给一段指定的内存空间起名,方便操作这段内存,相当于被某块内存起了个别名。
typedef声明
typedef是在计算机编程语言中用来为复杂的声明定义简单的别名, 它与宏定义有些差异。它本身是一种存储类的关键字,与auto、 extern、mutable、static、register等关键字不能出现在同一个表达式中
- typedef 可以声明各种类型名,但不能用来定义变量。
- 用typedef只是对已经存在的类型增加一个类型名,不能创造新的类型
- 当在不同源文件中用到同一类型数据(尤其是像数组、指针、结构体、共用体等类型数据)时,常用 typedef 声明一些数据类型,以提高编程效率
- typedef 有利于程序的通用与移植。有时程序会依赖于硬件特性,用 typedef 便于移植
局部变量
在 函数 内部声明/定义的变量叫局部变量,局部变量的作用域仅限 于函数内部。同时,在函数内部定义的变量,函数的 参数 和 返回 值,if 和 for 结构内部使用的变量等都是局部变量。
当存在全局变量和局部变量同名的时候,在函数内,局部变量会覆 盖全局变量。
使用 {} 可以限制变量的作用
全局变量
在函数外部声明/定义的变量叫全局变量,C++ 全局变量作用域在整个文件都有效。
静态变量
静态存储区的变量是在程序刚开始的时候就会完成初始化,也是整 个程序生命周期的唯一一次初始化。
静态存储区中一般存储两种变量:static 变量和全局变量。
static变量在函数内定义局部变量的时候,作用域只在其函数内, 但是生存周期为整个源程序。即只可以在定义该变量的函数内进行 使用,但是退出该函数后,该变量一直存在,但不可以进行使用。
c++存储类
存储类用于定义C++程序中变量和函数的生命周期和可见性
有五种类型的存储类,可以在C++程序中使用
- 自动(Automatic)
- 寄存器(Register)
- 静态(Static)
- 外部(External)
- 可变(Mutable)
auto 自动存储类
auto是所有局部变量的默认存储类。
auto关键字自动应用于所有局部变量。
{
auto int v1;
float v2 = 99.1;
}
上面的例子定义了两个具有相同存储类的变量,auto只能在函数中使用。
static 静态存储
静态变量只初始化一次,直到程序结束。
它保留可在多个函数之间调用的值。
静态变量由编译器提供的一个默认值:0。
register 注册存储类
寄存器变量在寄存器中分配存储器而不是RAM。 其大小与寄存器 大小相同。 它比其他变量具有更快的访问速度。
建议仅使用寄存器变量进行快速访问!
ex:在计数器中。
register int count=0;
注意:不能得到寄存器变量的地址
extern 外部存储类
extern变量对所有程序都可见。
如果两个或多个文件共享相同的变量或函数,则使用它。
extern int v1 = 0;
多文件编程
多文件编程概念
为了方便分工或后期的维护,分散代码应遵循一个基本原则:实现相同功能的代码应存储在一个文件中。
C++ 代码文件根据后缀名的不同,大致可以分为如下几类:
.h:头文件
.hpp:头文件,header plus plus 的缩写,混杂着 .h 的声明 .cpp 的定义,OpenCV 采用
.cpp:源文件,windows
.cc:源文件,Unix/Linux
又或者是有一天,你写出了很牛的功能代码,出于版权和保密考虑, 大多是已经编译好的二进制文件,可能仅包含 .h 文件
// 1.student.h
void printInfo();
// 2.student.cpp
#include "sudent.h"
//printInfo 定义
// 3.main.cpp
#include "student.h"
int main(){
// ... }
步骤
- 在资源管理器-解决方案中,找到头文件
- 在头文件文件夹上右键->添加->新建项
- 选择头文件(.h)->在名称处起名***.h
- 点击添加
- 编写代码 (注意:要包含***.h文件)
#include “.h” 即可使用*
include <> 和 #include ""的区别
- #include <>
#include <>引用的是编译器的类库路径里面的头文件。
一般用于引用标准头文件,如stdio.h,string.h等
- #include " ”
#include ""引用的是项目相对路径中的头文件
一般用于引用自定义的头文件。
如果使用#include “” ,首先会在当前项目所在文件夹下寻找是否有对应的头文件,如果没有, 还是会到编译器自带头文件目录中查找。
例如,使用#include “stdio.h” ,如果项目中不包含stdio.h这个头文件,则还是会定位到标准头 文件中查找stdio.h这个文件。
防止头文件重复包含
使用宏定义避免重复引入
#ifndef _NAME_H
#define _NAME_H
//头文件内容
#endif
_NAME_H
是宏的名称
注意:设置的宏名必须是独一无二的,不要和项目中其他宏的名称相同
当程序中第一次 #include 该文件时,由于 _NAME_H 尚未定义,所以会定义 _NAME_H 并执行 “头文件内容”部分的代码;当发生多次 #include 时,因为前面已经定义了 _NAME_H,所以不 会再重复执行“头文件内容”部分的代码。
可移植性强。
使用#pragma once避免重复引
#pragma once //放在文件开头位置
#ifndef 是通过定义独一无二的宏来避免重复引入的,意味着每次引入头文件都要进行识别,所以效率不高。 但考虑到 C 和 C++ 都支持宏定义,所以项目中使用 #ifndef 规避可能出现的“头文件重复引入”问题,不会影响 项目的可移植性
和 ifndef 相比
#pragma once 不涉及宏定义,当编译器遇到它时就会立刻知道当前文件只引入一次,所以效率很高。
但值得一提的是,并不是每个版本的编译器都能识别 #pragma once 指令,老版本的编译器有些是不支持该指令(执行时会发出警告, 但编译会继续进行),即 #pragma once 指令的兼容性不是很好
除此之外,#pragma once 只能作用于某个具体的文件,而无法像 #ifndef 那样仅作用于指定的一段代码
目前,几乎所有常见的编译器都支持 #pragma once 指令,甚至于 V S 2017 新建头文件时就会自带该指令。可以这么说,在 C/C++ 中, #pragma once 是一个非标准但却逐渐被很多编译器支持的指令。
用_Pragma操作符
_Pragma(“once”)
//放在文件开头位置
C99 标准中新增加了一个和 #pragma 指令类似的 _Pragma 操作符,其可以看做是 #pragma 的增强版,不仅可以实现 #pragma 所有的功能,更重要的是, _Pragma 还能和宏搭配使用。
考虑到编译效率和可移植性,#pragma once 和 #ifndef 经常被结合 使用来避免头文件被重复引入
#pragma once
#ifndef _NAME_H
#define _NAME_H
//头文件内容
#endif
当编译器可以识别 #pragma once 时,则整个文件仅被编译一次!
如果编译器不识别 #pragma once 指令,此时仍有 #ifndef在发挥作用