变量的作用域与存储分配

来源:互联网 发布:ldap连接mysql 编辑:程序博客网 时间:2024/05/06 14:21
1.变量的数据类型和存储类型

C语言中,每一个变量都有两个属性:数据类型和存储类型。数据类型即常说的字符型、整型、浮点型;存储类型则指变量在内存中的存储方式,它决定了变量的作用域和生存期。

变量的存储类型有以下四种:auto(自动)、register(寄存器)、extern(外部)和static(静态)。其中autoregister用于声明内部变量,auto变量是存储在栈中的,register变量是存储在寄存器中的。static用于声明内部变量或外部变量,extern用于声明外部变量,它们是存储在静态存储区的。

变量声明的一般形式:<</font>存储类型> <</font>数据类型> <</font>变量名列表>

当声明变量时未指定存储类型,则内部变量的存储类型默认为auto型,外部变量的存储类型默认为extern型。

外部变量有两种声明方式:定义性声明和引用性声明。

定义性声明是为了创建变量,及变量需要分配内存。引用性声明是为了建立变量与内存单元之间的关系,表示要引用的变量已在程序源文件中其他地方进行过定义性声明。定义性声明只能放在函数外部,而引用性声明可放在函数外部,也可放在函数内部。

extern int b;//引用性声明,也可放在函数fun

void fun()

{

    printf("d%",b);//输出

}

extern int b=5;//定义性声明,可以省略关键字extern

2.变量的作用域

变量的作用域是指一个范围,是从代码空间的角度考虑问题,它决定了变量的可见性,说明变量

在程序的哪个区域可用,即程序中哪些行代码可以使用变量。作用域有三种:局部作用域、全局作用域、文件作用域,相对应于局部变量(local variable)、全局变量和静态变量(global variable)。

(1)局部变量

大部分变量具有局部作用域,它们声明在函数(包括main函数)内部,因此局部变量又称为内部变量。在语句块内部声明的变量仅在该语句块内部有效,也属于局部变量。局部变量的作用域开始于变量被声明的位置,并在标志该函数或块结束的右花括号处结束。函数的形参也具有局部作用域。

#include

using namespace std;

 

int main()

{

    int x = 0;

    {

        int x=1;

        cout << x << endl;

        {

            cout << x << endl        

            int x = 2; // "x = 1" lost its scope here covered by "x = 2"

            cout << x << endl// x = 2

            // local variable "x = 2" lost its scope here

        }

        cout << x << endl// x = 1

        // local variable "x = 1" lost its scope here

    }

    cout << x << endl;

    // local variable "x = 0" lost its scope here

    return 0;

}

(2) 全局变量及extern关键字

全 局变量声明在函数的外部,因此又称外部变量,其作用域一般从变量声明的位置起,在程序源文件结束处结束。全局变量作用范围最广,甚至可以作用于组成该程序 的所有源文件。当将多个独立编译的源文件链接成一个程序时,在某个文件中声明的全局或函数,在其他相链接的文件中也可以使用它们,但是用前必须进行extern外部声明。extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。

以下是MSDNC/C++extern关键字的解释:

The extern Storage-Class SpecifierC

A variable declared with the extern storage-class specifier is a reference to a variable with the same name defined at the external level in any of the source files of the program. The internal extern declaration is used to make the external-level variable definition visible within the block. Unless otherwise declared at the external level, a variable declared with the extern keyword is visible only in the block in which it is declared.

The extern Storage-Class SpecifierC++

The extern keyword declares a variable or function and specifies that it has external linkage (its name is visible from files other than the one in which it's defined). When modifying a variable, extern specifies that the variable has static duration (it is allocated when the program begins and deallocated when the program ends). The variable or function may be defined in another source file, or later in the same file. Declarations of variables and functions at file scope are external by default.

    A.cpp 文件中,有一个全局变量a,和一个函数:func();

//A.cpp 文件:

……

int a;   //全局变量a的作用域开始于此,结束与整个程序源文件

void func()

{

  ……

}

……

我们希望在B.cpp 或更多其它文件可以使用到变量a和函数func(),必须在合适的位置声明二者:

//B.cpp 文件:

……

extern int a;        //a 由另一源文件(A.cpp)定义

extern void func();  //func 由另一源文件(A.cpp)定义

a = 100;

func();

……

这里例子中,合适的位置是在B.cpp文件里。其它合适的位置,比如在头文件里的例子。

需要强调的是函数的定义默认就是外部的,所以上面func()之前的extern也可以省略。

在使用extern 声明全局变量或函数时,一定要注意:所声明的变量或函数必须在,且仅在一个源文件中实现定义。如果你的程序声明了一个外部变量,但却没有在任何源文件中定义它,程序将可以通编译,但无法链接通过。

另外,extern也可用来进行链接指定。C++中的extern "C"声明是为了实现C++C及其它语言的混合编程,其中被extern "C"修饰的变量和函数是按照C语言方式编译和连接的。

如果C++调用一个C语言编写的.DLL时,当包括.DLL的头文件或声明接口函数时,应加extern "C" { }

In C++, when used with a string, extern specifies that the linkage conventions of another language are being used for the declarator(s). C functions and data can be accessed only if they are previously declared as having C linkage. However, they must be defined in a separately compiled translation unit.

Microsoft C++ supports the strings "C" and "C++" in the string-literal field. All of the standard include files use the extern "C" syntax to allow the run-time library functions to be used in C++ programs.

The following example shows alternative ways to declare names that have C linkage:

// testExtern.cpp

// compile with: /c

// Declare printf with C linkage.

extern "C" int printf( const char *fmt, ... );

// 包含C语言头文件

extern "C" {  

   #include

}

//  声明函数ShowChar和 GetChar为按C方式编译链接函数

extern "C" {

   char ShowChar( char ch );

   char GetChar( void );

}

//调用已有C函数,定义函数ShowChar和 GetChar

extern "C" char ShowChar( char ch ) {

   putchar( ch );

   return ch;

}

extern "C" char GetChar( void ) {

   char ch;

   ch = getchar();

   return ch;

}

// Declare a global variable, errno, with C linkage.

extern "C" int errno;

(3) 静态变量及static关键字

文件作用域是指在函数外部声明的变量只在当前文件范围内(包括该文件内所有定义的函数)可用,但不能被其他文件中的函数访问。一般在具有文件作用域的变量或函数的声明前加上static修饰符。

static静态变量可以是全局变量,也可以是局部变量,但都具有全局的生存周期,即生命周期从程序启动到程序结束时才终止。

#include

void fun()

{

    static int a=5;//静态变量a是局部变量,但具有全局的生存期

      a++;

      printf("a=%d\n",a);

}

void main()

{

    int i;

    for(i=0;i<2;i++)

        fun();

    getchar();

}

输出结果为:

a=6

a=7

static操作符后面生命的变量其生命周期是全局的,而且其定义语句即static int a=5;只运行一次,因此之后再调用fun()时,该语句不运行。所以f的值保留上次计算所得,因此是6,7.

由于静态变量或静态函数只在当前文件(定义它的文件)中有效,所以我们完全可以在多个文件中,定义两个或多个同名的静态变量或函数。这样当将多个独立编译的源文件链接成一个程序时,static修饰符避免一个文件中的外部变量由于与其他文件中的变量同名而发生冲突。

比如在A文件和B文件中分别定义两个静态变量a

A文件中:static int a;

B文件中:static int a;

这两个变量完全独立,之间没有任何关系,占用各自的内存地址。你在A文件中改a的值,不会影响B文件中那个a的值。

参考:

《程序设计与C语言》梁力

《白话C++》南郁

Visual C++面向对象编程教程》王育坚