2014-01-08 80 views
2

我想知道人们是否能够对“静态”的用法进行阐述。我从来没有遇到过我已经明确声明变量或方法为静态的问题。我明白,当将某些东西声明为“静态”时,它会被塞入到程序的数据段中,类似于全局变量,因此该变量可用于运行程序。如果是这种情况,为什么不把一个静态变量作为一个全局变量。地狱,为什么不使用新的或malloc将这个变量放在堆上,这两种方法都可以确保变量在整个程序运行过程中都可用。Static vs New/Malloc

+0

'void foo(){auto p = new int {};/*东西/ *}'哦拍摄,每次丢失指针和新的记忆。 – chris

+0

如果你想要清楚地理解存储,链接,名称,变量,对象,声明,定义,范围,块,生命周期......你必须愿意真正地对大量的细节和琐事感到热情。除非你真的只要坚持简单的操作语义并继续... –

回答

8

static在C语言中有多重含义,C++堆得更多。

在文件范围声明(我认为问题的关键)中,静态控制标识符的可见性。

让我们抛开C++并使用C语言概念。

名称对象或函数具有的文件范围标识符联动。链接可以是外部(程序范围)或内部(在一个翻译单元内)。

static指定内部链接。

这很重要,因为如果具有内部链接的名称以多个单位出现,则这些出现是不相关的。一个模块可以具有静态foo功能,而另一个模块可以具有不同的foo功能。它们都存在,可以通过各自单位的名称foo联系。

这是不可能的与外部联动:必须有一个foo

malloc创建一个在程序中随处可用的对象,只要它没有被释放,但是具有不同的意义。如果您有指针,则该对象可用。指针是一种“运行时间名称”:访问对象的访问键。如果你知道它的名字(在编译时),并且该对象和函数与你尝试访问它的地方相关联的类型是正确的,那么链接使对象或函数可用。

在动态操作系统中,多个程序开始生效并终止,其静态数据和函数(无论它们是否具有外部或内部链接)的存储实际上是动态分配的。加载程序的系统例程必须执行类似于malloc的操作来获取程序所有固定区域的内存。

有时C程序甚至使用malloc,即使是通过全局指针全局引用的“单例”对象。这些对象的行为类似于事实上的静态变量,因为它们基本上具有几乎与整个程序相同的生命周期,并且可以通过指针来访问,该指针通过名称访问。如果对象具有直到运行时才知道的属性(如大小),或者它们的初始化开销很大并且并非总是需要它们(只有在程序中出现某些情况时),才会很有用。


补充仿真陈述约staticextern

  • 在C中,在文件范围,extern确保一个对象,其中省略初始化器的声明,事实上是一个声明。没有extern这是一个试探性的定义,但如果存在一个初始化器,那么它就是一个定义。

  • 在C中,在文件范围extern并不意味着“这个声明有外部链接”,令人惊讶的是。一个extern声明继承了前一个同名声明的链接。

  • C中的块范围extern表示“该名称正在引入此范围,是指外部定义与外部链接”。链接从名称的前一个文件范围声明(如果存在)继承,否则它是外部的。

  • 对象上的块范围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_caststatic无关;它们共同之处在于“静态”,意思是“在程序运行时间之前”:静态存储在运行时间之前确定,静态转换的转换也是在编译时确定的(没有运行时类型信息)。

+0

谢谢你解释得非常清楚。我想这是关于你的程序的用例和设计的全部内容。不过很高兴知道它们是什么 – AyBayBay

+0

我会坚持我的全局变量和mallocs – AyBayBay

+1

全局变量是邪恶的。应避免动态内存。多个编写者可以设置一个全局变量,没有控制或访问受限。动态内存分配会产生内存泄漏或碎片(这需要垃圾回收)。所以学会最小化全局变量并避免动态内存分配。尤其在嵌入式系统上。 –