我想知道人们是否可以对“静态”的使用有所了解。我从来没有遇到过我明确声明变量或方法为静态的问题。我理解,当声明某些东西为“静态”时,它会被填充到程序的数据段中,类似于全局变量,因此变量可以在程序运行时访问。如果是这种情况,为什么不将静态变量设为全局变量。地狱,为什么不使用new或malloc将这个变量放在堆上,这两种方法都确保在整个程序运行期间变量可用。
答案 0 :(得分:8)
static
在C中有多重含义,而C ++则更多。
在文件范围声明中(我认为问题是关于),static控制标识符的可见性。
让我们留出C ++并使用C概念。
名称对象或函数的文件范围标识符具有链接。链接可以是外部(程序范围)或内部(在一个翻译单元内)。
static
指定内部链接。
这很重要,因为如果具有内部链接的名称出现在多个单元中,则这些出现不相关。一个模块可以具有静态foo
功能,而同一程序中的另一个模块可以具有不同的foo
功能。它们都存在,并且可以通过名称foo
从各自的单位到达。
外部链接无法做到这一点:必须有一个foo
。
malloc
创建一个可能在程序中随处可用的对象,只要它没有被释放,但在不同的意义上。如果有指针,则该对象可用。指针是一种"运行时名称":访问该对象的访问键。如果您知道其名称(在编译时),并且该对象和函数相对于您尝试访问它的位置具有正确的链接类型,则Linkage会使对象或函数可用。
在一个动态操作系统中,多个程序生效并终止,其静态数据和函数(无论它们是否具有外部或内部链接)的存储实际上是动态分配的。加载程序的系统例程必须执行与malloc
类似的操作,以获取程序的所有固定区域的内存。
有时C程序使用malloc
即使对于" singleton"通过全局指针全局引用的对象。这些对象的行为类似于事实上的静态变量,因为它们的生命周期几乎与整个程序的生命周期相同,并且可以通过指针访问,该指针可以通过名称访问。如果对象具有直到运行时才知道的属性(例如大小),或者它们的初始化很昂贵并且并不总是需要它们(仅在程序中出现某些情况时),这将非常有用。
关于static
和extern
的补充事实:
在C中,在文件范围内,extern
确保省略初始化程序的对象声明实际上是一个声明。没有extern
它是一个暂定的定义,但是如果存在初始化器,那么它就是一个定义。
在C中,文件范围extern
并不意味着"这个声明有令人惊讶的外部链接" extern
声明继承了先前同名声明的链接。
C中的块范围extern
表示"此名称引入此范围,引用外部定义与外部链接&# 34 ;.该链接继承自名称的先前文件范围声明(如果存在),否则它是外部的。
对象上的块范围static
控制不是链接,而是存储持续时间。每次进入块时都不会实例化static
对象;它的单个副本存在,可以在程序启动之前初始化。 (在C ++中,非常量表达式可以初始化此类对象或其成员;在这种情况下,初始化会在块的第一次执行时发生。)
块范围static
函数声明声明具有内部链接的函数。
在块作用域中,无法声明具有内部链接的外部对象名称。矛盾的是,以下代码段中的第一个extern
声明是正确的,但第二个,块范围声明是错误的!
static int name; /* external name with internal linkage */
extern int name; /* redundant redeclaration of the above */
void foo(void)
{
int name; /* local variable shadowing external one */
{
/* attempt to "punch through" shadow and reach external: */
extern int name; /* ERROR! */
}
}
显然,"外部"在任何功能之外都有一个模糊的含义"和"程序范围的联系"这种歧义卷入了extern
关键字。
在C ++中,static
具有其他含义。在类声明中,它声明了静态成员函数"属于类范围并且与非静态成员函数具有相同的类实例访问权限,但不在对象上调用(没有隐式this
参数)。标记为static
的类数据成员具有单个类范围的实例;它们不是针对每个对象实例化的。 (不幸的是,他们没有像真正的面向对象的类变量那样正确地参与继承,可以在派生类中重写为实例,反之亦然。)
在C ++中,使用未命名的namespace
而不是static
可以实现类似于内部链接的隐私。命名空间使内部/外部链接概念主要成为C兼容性的过时机制。
C ++在特殊extern
语法中涉及extern "LANG"
(例如extern "C"
)。
static_cast
与static
无关;他们的共同点是"静态"意思是"在程序运行时之前":静态存储是在运行时之前确定的,静态强制转换的转换也是在编译时确定的(没有运行时类型信息)。