作用域 生存期 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作用域是跨文件的。而在类内部的话,类的作用域是不跨文件的。
————————————————————————————————————————————————
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作用域是跨文件的。而在类内部的话,类的作用域是不跨文件的。
相关文章推荐
- C++ 标识符作用域以及对象生存期
- 生存期与作用域
- C++中变量生存期,作用域,存储位置总结
- (转-经典-数据段)C++回顾之static用法总结、对象的存储,作用域与生存期
- C++中四种对象生存期和作用域以及static的用法总结分析
- 08.作用域和生存期
- 内存操作(指针,变量的生存期及作用范围,良好的动态内存申请和释放习惯)(
- 作用域与生存期
- static变量的生存期及作用域
- C/C++的变量生存期和作用域
- 指针,变量的生存期及作用范围,良好的动态内存申请和释放习惯
- 浅谈C/C++中static extern关键字的作用
- C语言中变量的生存期及作用域介绍
- 作用域,可见性,生存期。
- C++回顾之static用法总结、对象的存储,作用域与生存期
- 第七讲:作用域.可见性.生存期.全局对象
- C++回顾之static用法总结、对象的存储,作用域与生存期
- 自动变量和开辟内存的生存期和作用域探讨
- 静态变量的生存期和作用域
- C++作用域和生存期