C和C ++中的静态变量

在C和C ++之间的任何函数之外声明为static的变量之间是否有任何区别。 我读到static意味着文件范围,并且文件外部不能访问变量。 我还读到在C中,全局变量是static 。 那么这是否意味着C中的全局变量无法在另一个文件中访问?

不,在这方面C和C ++没有区别。

阅读这个关于C程序中static含义的答案 。 在C ++中,还有一些与使用static类变量(而不是实例变量)相关的其他含义。

关于全局变量是static – 仅从内存分配的角度来看(它们被分配在数据段上,就像所有全局变量一样)。 从能见度的角度来看:

 static int var; // can't be seen from outside files int var; // can be seen from outside files (no 'static') 

这里有两个概念“静态链接 (或范围)”和静态分配 “。

在函数外部,关键字指的是链接,里面指的是分配。 函数外的所有变量都隐式地具有静态分配。 也许是一个不幸的设计,但它确实存在。

C和C ++是一样的。

static做了两件不同的事情。

对于在函数作用域外声明的变量,它会更改变量的可见性(链接)。 变量将是一个全局变量,因为它在函数范围之外。 如果它不是静态的,它将具有通用链接(可见性),因此与此链接在一起的任何代码都可以访问它(它们可能必须将其声明为extern)。 如果变量在函数作用域之外并且是静态的,那么它仍然是一个全局变量,因为它始终存在并保持其值,但是同一编译单元(.c文件和包含的任何.h)之外的代码都不能访问它。

对于在函数作用域内声明的变量,static会更改存储变量的位置。 如果它不是静态的,它将是一个自动变量,这意味着它会在函数退出时消失,并在再次输入函数时重新出现(在堆栈中)。 退出函数时它会丢失它的值。 并且在函数退出后对它的任何引用(指向它)都是无效的。 如果在函数作用域内声明的变量是静态的,那么它使它不是自动变量而是全局分配的变量。 因此变量将在函数退出后存在,因此将在函数的调用之间保持其值,并且即使在函数退出之后,对它的任何引用(指针)也是有效的。 请注意,在这两种情况下,变量的范围仅在该函数内,因此无法从函数范围外直接访问它(但仅通过保存的引用)。

静态做的最后一件事是在运行变量的初始值设定项(即int foo = 5)时进行更改。 对于分配是全局的所有情况(除了自动分配之外的每种情况),初始化程序仅在程序执行开始时运行一次。 它在main()运行之前运行,因此如果初始化程序不仅仅是一个常数而是运行一些代码,那么你可以得到一些不太理想的结果。 对于自动情况,每次输入函数时都会运行初始化程序,在这种情况下,它始终在输入main()之后运行。

我想在C和C ++中添加Southern Hospitality的回答静态变量

以下评论:

在C ++中不推荐使用static来表示“本地到翻译单元”(href =“http://rads.stackoverflow.com/amzn/click/0201700735”C ++编程语言:特别版,附录B.2.3,已弃用特征)。

您应该使用未命名的命名空间:

 static int reply = 42; // deprecated namespace { int reply1 = 42; // The C++ way } 

正如Southern Hospitality已经说过的那样,全局对象的初始化顺序是不确定的。 在这种情况下,您应该考虑使用单点模式的href =“http://en.wikipedia.org/wiki/Singleton_pattern#C.2B.2B”。

更新:GMan评论我的回答:

“订单是按翻译单位定义的,……”:这真的让我不知所措,所以我在C ++编程语言中查了一下。

在第9.4.1节“非局部变量的初始化”中,Stroustrup教授建议“返回引用的函数是全局变量的一个很好的替代”:

 int& use_count() { static int uc = 0; return uc; } 

“对use_count()调用现在充当一个在第一次使用时初始化的全局变量。例如:”

 void f() { std::cout << ++use_count() << '\n'; } 

根据我的理解,这与Singleton模式非常相似。

GMan进一步评论道:“我们需要限制我们创建这些对象的能力,并提供全局访问权限。” 对一个人的限制是否与问题中的任何事情有关? 我们可能需要全球一个,但是谁说我们不想在其他地方使用它?“

Singleton(127)(Gamma等,Design Patterns)的一些引用:

“Singleton模式是对全局变量的改进。它避免了使用存储唯一实例的全局变量来污染名称空间。”

“这种模式可以让你轻松改变主意并允许使用Singleton类的多个实例。”

单身人士按照他们第一次使用的顺序进行初始化。

在Herb Sutter,Andrei Alexandrescu,C ++编码标准中,第10项说:

“避免共享数据,尤其是全球数据。”

因此,我经常使用单身人士来避免全球数据。 但是,当然,由于一切都是可以过度使用的,这可能是过度使用Singleton模式。 (Johshua Kerievsky在他的“重构模式”一书中称之为“单身性炎症”。)

更新2:

(对不起,但我不能写评论,因此这个更新。)

贾尔夫在评论中写道:“当四人帮他们撰写关于单身人士模式时,他们正在吸食非法的东西。”

显然,其他C ++开发人员也吸食了有趣的物质。 例如,Herb Sutter(他在第二个C ++标准,C ++ 0x开发期间担任ISO C ++标准委员会秘书和主席十多年,并担任Microsoft C ++ / CLI的首席架构师.Herb目前用于Microsoft平台的Prism内存模型的设计者和用于并行编程的Visual C ++的Concur扩展,在C ++编码标准中写道,第21项:

“当你需要一个可能依赖于另一个的(命名空间级别)变量时,请考虑Singleton设计模式;仔细使用它可以通过确保在第一次访问时初始化对象来避免隐式依赖。但是,Singleton是一个全局变量绵羊的衣服,被相互或循环的依赖打破。“

因此,如果可以,请避免使用全局数据。 但是,如果必须在单独的转换单元中使用全局数据,则Singleton应该是可执行特定初始化序列的可接受解决方案。

请注意,在Java语言中,全局数据甚至不存在。 显然,使用Singleton设计模式替代/模拟全局数据。

(因为我在Java团队的日常工作中工作,我努力使我的C ++程序与Java程序最大程度地相似。例如,每个类都位于其自己的源文件/翻译单元中。)

对你的问题并不是一个直接的答案,但如果你同时使用C和C ++,那么要注意与之密切相关。

在C ++中,与C不同,声明为“const”的全局变量对于转换单元是隐式本地的,因为AS IF使用了“静态”。

例:

 // file A extern const int glob; // file B const int glob = 42; 

如果您使用C编译器但不使用C ++编译器,这将起作用。 在C ++中,文件B中的glob变量不能在文件A中使用,链接器将生成“未解析的引用”错误。