您的位置:首页 > 其它

作用域 生存期 static extern..........

2014-09-01 15:36 68 查看
static(c中定义的关键字1、被其修饰者 外部无法使用(相反的都可以使用extern在外部使用) 2、函数局部变量使用成为静态的放入静态池-生存期改变。c++进行了扩充,使它在类中有了特殊作用)

————————————————————————————————————————————————

1、 static局部变量的”记忆性”与生存期的”全局性”

所谓”记忆性”是指在两次函数调用时, 在第二次调用进入时, 能保持第一次调用退出时的值.

示例程序一

#include <iostream>

using namespace std;

void staticLocalVar()

{

static int a = 0; // 运行期时初始化一次, 下次再调用时, 不进行初始化工作

cout<<"a="<<a<<endl;

++a;

}

int main()

{

staticLocalVar(); // 第一次调用, 输出a=0

staticLocalVar(); // 第二次调用, 记忆了第一次退出时的值, 输出a=1

return 0;

}

应用:

利用”记忆性”, 记录函数调用的次数(示例程序一)

利用生存期的”全局性”, 改善”return a pointer / reference to a local object”的问题. Local object的问题在于退出函数, 生存期即结束,. 利用static的作用, 延长变量的生存期.

示例程序二:

// IP address to string format

// Used in Ethernet Frame and IP Header analysis

const char * IpToStr(UINT32 IpAddr)

{

static char strBuff[16]; // static局部变量, 用于返回地址有效

const unsigned char *pChIP = (const unsigned char *)&IpAddr;

sprintf(strBuff, "%u.%u.%u.%u", pChIP[0], pChIP[1], pChIP[2], pChIP[3]);

return strBuff;

}

注意事项:

1. “记忆性”, 程序运行很重要的一点就是可重复性, 而static变量的”记忆性”破坏了这种可重复性, 造成不同时刻至运行的结果可能不同.

2. “生存期”全局性和唯一性. 普通的local变量的存储空间分配在stack上, 因此每次调用函数时, 分配的空间都可能不一样, 而static具有全局唯一性的特点, 每次调用时, 都指向同一块内存, 这就造成一个很重要的问题 ---- 不可重入性!!!

这样在多线程程序设计或递归程序设计中, 要特别注意这个问题.

(不可重入性的例子可以参见<effective C++ (2nd)>(影印版)第103-105页)

2、外部静态变量/函数 -------限制作用域在内部
生存期依旧全局(可用namespace xx来等价实现???)

在C中static有了第二种含义:用来表示不能被其它文件访问的全局变量和函数。, 但为了限制全局变量/函数的作用域, 函数或变量前加static使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)。注意此时,
对于外部(全局)变量, 不论是否有static限制, 它的存储区域都是在静态存储区, 生存期都是全局的. 此时的static只是起作用域限制作用, 限定作用域在本模块(文件)内部.

使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名。

示例程序三:

//file1.cpp

static int varA;

int varB;

extern void funA()

{

……

}

static void funB()

{

……

}

//file2.cpp

extern int varB; // 使用file1.cpp中定义的全局变量

extern int varA; // 错误! varA是static类型, 无法在其他文件中使用

extern vod funA(); // 使用file1.cpp中定义的函数

extern void funB(); // 错误! 无法使用file1.cpp文件中static函数

3、静态数据成员/成员函数(C++特有)

C++重用了这个关键字,并赋予它与前面不同的第三种含义:表示属于一个类而不是属于此类的任何特定对象的变量和函数.

————————————————————————————————————————————————

1. 存储类型(Storage Class),是C语言与C++语言的标准中,变量与函数的可访问性(即作用域范围scope)与生存期(life time)的类型。存储类型可分为auto、register、static、extern、mutable、thread_local等。上述关键字有各自使用域。如:

namepace nnn

{

auto void func();//错误

auto int i;//错误

static int j;//正确,此时static的文件可见性消失,被限制为namespace可见性

}

class C

{

public:

auto int i;//错误

};

类的可见性,比namespace特殊一点,需要对象绑定,如果显示声明static可以消除对象绑定。

详见百度百科。

2.文件中直接声明非const变量,默认是extern的,即全局作用域全局可见性。

文件:1.cpp

int i; // 等价于extern int i = 默认初始化。

文件:2.cpp

extern int i;

上面程序中,2.cpp的i变量在1.cpp中定义。

3. 文件中声明const变量,具有文件作用域文件可见性(和static修饰符一样)。

文件1.cpp

const int i = 0; //等价于static const int i = 0;

文件:2.cpp

extern int i;

上面程序中,由于1.cpp中i是文件可见性,2.cpp看不到i的定义,所以2.cpp的i还没有定义。将2.cpp中修改为extern const int i = 0; 出现一个问题:由于2.cpp的i是全局可见的,文件1.cpp编译时可以看到2.cpp的i,会不会出现i重定义。答案:不会,因为不同在同一个作用域是不会出现重定义的。如:

int i;

{

int i;

}

4. 对于文件中直接声明函数也是默认extern的(尽管函数有const属性,即函数定义一次不能再次修改)。

文件:1.cpp

void func() {};

文件:2.cpp

void func() {};

在编译时会出现函数重定义。在重定义检测方面根据编译器不同而匹配。如将1.cpp文件中改为int func() {return 0;} gun c就会出现重定义,而vs不出现重定义,在同一个文件函数名相同一定出现重定义。extern void func() 和void func()一样,extern void func(){} 也和extern void func()一样,所以在函数在外部定义的话,不用加extern。

5. 对于inline函数

liline函数有时不会解释成liline,那该函数自动转成全局的。如果其他文件有一个全局的该函数,在调用该函数(注意,不调用则不会)会重定义。

如:在带main函数的文件中定义

main.cpp

inline void func() {}

int main()

{

func();//函数中使用了inline函数就会出现重定义。

}

body.cpp

void func() {}

有可能出现重定义。虽然inline函数作用域是文件的,如:

文件1.cpp

inline void func(){}

文件2.cpp

inline void func(){}

这两者互不可见。但是对于下段程序

文件1.cpp

inline void func(){}

void funcx() { func() }//调用会出现重定义

文件2.cpp

void func() {}

inline函数在调用时,会检查上层作用域,目的是防止inline函数定义模糊。

6. 对于类的作用域和namespace的作用域

类内定义具有文件作用域和namespace作用域,类外定义,具有全局作用域和namespace作用域,注意namespace作用域是可以跨文件的。(全局作用域的一个名字,两种类型在不同文件是不冲突的,而一个文件中一个名字只能出现一次,即使不同类型)。class比namespace域表示更复杂一点。类名和ns名是文件作用域的,但其有定义了一个作用域,这个作用域却又是跨文件的。

类的复杂的一点是:两个文件中同名类中可以有同名变量,而ns中却不可以。因为ns作用域是跨文件的。而在类内部的话,类的作用域是不跨文件的。







内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: