您好,欢迎访问三七文档
第3章数据1.作用域4种不同的作用域:文件作用域,函数作用域,代码块作用域和原型作用域。1)代码块作用域位于一对花括号之间的所有语句称为一个代码块。任何在代码块的开始位置声明的标识符都具有代码作用域(blockscope),表示它们可以被这个代码块中的所有语句访问。但位于函数内,则变量的作用是从其声明处开始,到其函数结束为止。例子如下:#includestdio.h例1-1:voidfun(){intc=30;printf(c=%d###,d=%d\n,c,d);intd=40;}intmain(){inta=10;printf(a=%d###,b=%d\n,a,b);intb=20;//fun();return1;}以上编译,报错:F:\test\scope\scope.cpp(7):errorC2065:'d':undeclaredidentifierF:\test\scope\scope.cpp(15):errorC2065:'b':undeclaredidentifier对于局部变量,如果声明时不赋初值,在编译时会报以下warning,但仍然可以编译通过。如例1-2:例1-2:intmain(){inta;printf(a=%d###d\n,a);return1;}编译提示如下:warningC4700:localvariable'a'usedwithouthavingbeeninitialized声明于每个代码块的变量无法被另一个代码块访问,因为它们的作用域并无重叠之处。由于两个代码块的变量不可能同时存在,所以编译器可以把它们存储于同一个内存地址。这种共享并不会带来任何危害,因为在任何时刻,两面三刀个非嵌套的代码块最多只有一个处于活动状态。如例1-3:例1-3:intmain(){if(0){inta=10;printf(a=%d###d\n,a);}else{inta=20;printf(a=%d###d\n,a);}return1;}编译正常通过,因为任何时刻,只有一个代码块处于活动状态。2)文件作用域任何在所有代码块之外声明的标识符都具有文件作用域(filescope),它表示这些标识符从它们的声明之处直到它所在的源文件结尾处都是可以访问的。在文件中定义的函数名也具有文件作用域,因为函数名本身并不属于任何代码块。如例1-4中,a的作用域是从其声明之处,到文件结尾都是可以访问的,所以fun()函数可以访问a。但b的作用域则是在函数fun()之后才声明的,可以函数fun()是不可以访问b的。例1-4:inta;voidfun(){a=10printf(a=%d###,b=%d\n,a,b);}intb=30;intmain(){fun();return1;}2.链接属性一个程序的的各个源文件是分别被编译出来的,当各个源文件分别被编译出来之后,所有的目标文件以及那些从一个或多个函数库中引用的函数链接在一起。标识符的链接属性(linkage)决定如何处理在不同文件中出现的标识符。标识符的作用域与它的链接属性有关,但这两个属性并不相同。链接属性有3种----external(外部),internal(内部)和none(无)。属于internal链接属性的标识符在同一个源文件内的(相同名字的标识符的)所有声明中,都指同一个实体,但位于不同源文件的多个(相同名字的标识符的)声明,则分属不同的实体。属于external链接属性的标识符不论声明多少次,位于几个源文件都表示同一个实体。(所以,不能在多个源文件中,声明同一个相同名字的标识符。)1)在任何一个源文件中声明一个变量,则这个变量的缺省情况下,其链接属性为external。2)static关键字:如果某个声明在正常情况下,具有external链接属性,在它前面加上static关键字可以使它的链接属性变为internal,如:staticintvar2那么这个变量var2就将为这个源文件所私有。在其他源文件(fun1.cpp)中,如果也链接到一个叫做var2的变量,那么它(fun1.cpp)所引用的是另一个不同的变量。例1-5:打印结果如下所示:可见,fun1.cpp与fun2.cpp中的var2为两个不同的实体。2)extern关键字:它为一个标识符指定external链接属性,这样就可以访问在其他任何位置定义的这个实体(如:fun1.cpp中的var2即为fun2.cpp中的var2)。这样一来,函数就可以在访问在其他源文件声明的外部变量了。例1-6:打印结果如下所示:3)如果两个不同的文件中,出现相同的标识符,且两个标识符都没有任何一个标明为extern,则编译会出错。如例1-7://fun1.cppintvar1=10;intvar2=30;voidfun1(void){printf(####fun_1####var1=%d\n,var1);printf(####fun_1####var2=%d\n,var2);}//fun2.cppexternintvar1;staticintvar2=20;voidfun2(void){printf(####fun_2####var1=%d\n,var1);printf(####fun_2####var2=%d\n,var2);}//fun1.cppintvar1=10;externintvar2;voidfun1(void){printf(####fun_1####var1=%d\n,var1);printf(####fun_1####var2=%d\n,var2);}//fun2.cppexternintvar1;intvar2=20;voidfun2(void){printf(####fun_2####var1=%d\n,var1);printf(####fun_2####var2=%d\n,var2);}//fun1.cppintvar1=10;intvar2;voidfun1(void){printf(####fun_1####var1=%d\n,var1);printf(####fun_1####var2=%d\n,var2);}//fun2.cppexternintvar1;intvar2=20;voidfun2(void){printf(####fun_2####var1=%d\n,var1);printf(####fun_2####var2=%d\n,var2);}则编译后链接时报错如下:fun2.obj:errorLNK2005:intvar2(?var2@@3HA)alreadydefinedinfun1.objDebug/test.exe:fatalerrorLNK1169:oneormoremultiplydefinedsymbolsfound3.存储类型变量的存储类型(storageclass)是指存储变量值的内存类型。变量的存储类型决定变量何时创建,何时销毁以及它的值将保持多久。有3个地方可以存储变量:普通内存,运行时堆栈,硬件寄存器。、1)凡是在任何代码块之外声明的变量总是存储于静态内存中,也就是不属于堆栈的内存,这类变量称为静态(static)变量。静态变量在程序运行之前创建,在程序的整个执行期间始终存在。它始终保持一个原始的值,除非给它赋一个不同的值或者程序结束。简而言之,即全局变量就是静态变量,全局变量存储于静态内存中。2)在代码块内部声明的变量的缺省的存储类型是自动的(automatic),也就是它存储于堆栈中,称为自动(auto)变量。简而言之,不带关键字static修饰的局部变量,就是自动变量,其存储于堆栈中。3)在代码块内部声明的变量,如果给它加上关键字static修饰,可以使它的存储类型从自动变量变为静态变量。注意:具有静态存储类型的变量在整个程序执行过程中一起存在,而不仅仅在声明它的代码块的执行时存在。但是,请注意:修改变量的存储类型,并不表示修改该变量的作用域,它仍然只能在该代码块内部按名字访问。如例1-8,变量a为全局变量,为静态变量,存储于静态内存中;变量b为局部变量,为自动变量,存储于堆栈中。例1-8://main.cppinta;voidfun(){a=10;intb=20;printf(a=%d####b=%d\n,a,b);}intmain(){fun();return1;}4)初始化静态变量在程序运行之前已经创建,当可执行文件载入到内存时,这个已经保存了正确初始值的位置将赋值给那个变量。如果不显示地指定静态变量的初始值,则其将初始化为0。自动变量在程序运行到执行该变量时才创建。事实上,函数的局部变量在函数的每次调用中可能占据不同的位置,基于这个理由,自动变量没有缺省的初始值,而显式的初始化将在代码块的起始处插入一条隐式的赋值语句。5)static的总结当static用于函数定义时,或用于代码块之外的变量声明时,static关键字用于修改标识符的作用链接属性,从external改为internal,但标识符的存储类型和作用域不受影响。(因为全局变量的存储类型是静态变量,作用域是文件作用域,即从声明到文件结尾处。)当static用于代码块内部的变量声明时,static关键字用于修改变量的存储类型,从自动变量修改为静态变量,但变量的链接属性和作用域不受影响(局部变量的链接属性是只在代码内按名字访问,作用域是从其声明开始处到代码块结束处)。用这种方式声明的变量在程序执行之前创建,并在程序的整个执行期间一直存在,而不是每次在代码块开始执行时创建,在代码块执行完毕后销毁。/*参考《C和指针》第3章数据*/Michael_Li2011-7-16初始化变量的定义指定了变量的类型和标识符,也可以为对象提供初始值。定义时指定了初始值的对象称为已初始化的(initialized)。C++支持两种初始化变量的形式:复制初始化(copy-initialization)和直接初始化(direct-initialization)。复制初始化用等号(=),直接初始化则把初始化式放在括号中:intvara(1024);//direct-initializationintvarb=10;//copy-initialization对于内置类型,复制初始化和直接初始化几乎没有差别,但对于类类型的对象来说,有些初始化仅能用直接初始化完成。内置类型变量是否自动初始化,取决于变量定义的位置。在函数体外定义且未被显式赋值的变量,都初始成0;在函数体外定义且被显式赋值的变量,都初始化成该所赋的值;在函数体里定义的内置类型变量不进行自动初始化。类类型变量的初始化如果定义某个类的变量时,没有提供初始化式,这个类也可以定义初始化时的操作。它是通过定义一个特殊的构造函数即默认构造函数(defaultconstructor)来实现的。如果没有提供初始化式,那么就会使用默认构造函数。还管变量在哪里定义,默认构造函数都会被使用。如果类具有默构造函数,那么就可以在定义该类的变量是不用显式地初始化变量。例如,string类定义了默认构造函数来初始化string变量为空字符串,即没有字符的字符串:std::stringemptyString;//emptyStringistheemptystring;emptyString=“”有些类没有默认构造函数。对于这些类来说,每个定义都必须提供显式的初始化式。没有初始值是根本不可能定义这种类型的变量的。声明和定义比较变量的定义(definition)用于为变量分配存储空间,还可以为变量指定初始值。在一个程序中,变量有且只有一个定义。变量的声明(declaration)用于向程序表明变量的类型和名字。但并不分配存储空间。定义也是声明:当定义变量时,我们就声明了它的类型和名字。可以通过使用关键字extern声明变量名而不定义它。不定义变量的声明包括对象名,对象类型和对象类型的关键字extern。externintvarA;//declaresbutdoesnotdefinev
本文标题:第3章数据
链接地址:https://www.777doc.com/doc-2193358 .html