我有一个包含静态变量的头文件,例如窗口宽度和高度。
我通过XML文件读取了这些变量的新值,但是这些更改在更改它的函数后似乎没有注册,超出了范围。
举例说明:
// These are in a separate header file
static int width = 0;
static int height = 0;
aClass::Init()
{
width = readFromXMLFile(); // returning 800
height = readFromXMLFile(); // returning 600
// Here width and height are 800/600
}
aClass::Run()
{
...
}
Main
{
Init()
// Here, width and height are 0/0 again
Run()
}
答案 0 :(得分:5)
如果你没有在某个地方声明一个静态的extern,你最终会得到的是每个编译单元的静态多个副本(同名)。
正确的例子:
test.h
extern int mystatic;
TEST.CPP
int mystatic = 0;
void myFunction() // or member funciton, who cares
{
mystatic = 42;
}
的main.cpp
#include "test.h"
int main()
{
std::cout << mystatic << std::endl; // prints 0
//
myFunction(); // or use classes and trigger the same
//
std::cout << mystatic << std::endl; // prints 42
return 0;
}
HTH
答案 1 :(得分:5)
等一下......你有
static int height = 0;
static int width = 0;
在头文件中?这将在每个包含标头的编译单元中创建文件范围的static
。如果要使用全局变量,则在标头中将它们声明为extern
,并在一个编译单元中定义它们。
答案 2 :(得分:3)
您应该在头文件extern
中声明静态变量,并在cpp文件中定义它们。
.h文件:
extern int foo;
.cpp文件:
int foo;
答案 3 :(得分:1)
我认为你误解了关键字static
。在C ++中,这个关键字有很多含义,都是松散相关的。
在顶层,不在类,结构或函数定义中,关键字static
创建了一种奇怪的全局变量。该全局变量仅在其出现的“编译单元”中可见。 “编译单元”的概念是通过C ++预处理器的工作方式创建的。
以#
开头的所有内容都不是C ++语言的一部分,而是预处理器的一部分。预处理器将所有这些指令和片段一起读取到编译单元。它扩展了所有宏,并将所有#include
指令替换为指令中提到的文件的内容。
使用gcc,您可以通过将-E
选项传递给编译器来查看结果。这将在编译C ++文件时向您显示生成的“编译单元”的内容。
您会注意到所有#include
ed头文件都成为编译单元的一部分。
现在,转到文件级静态变量......
这些变量是编译单元的本地变量。如果在另一个编译单元中声明具有相同名称的文件级静态变量,它们将是不同的变量。如果更改一个编译单元中的值,则它们与其他编译单元中的这些变量的值无关。
还记得头文件最终是如何被复制到每个编译单元的吗?
这意味着在头文件中声明的文件级静态变量最终在每个编译单元中都有副本。它们看起来似乎是全球性的,但实际上会有许多不相互作用的副本。
在您的情况下,您可以通过使它们成为完全全局变量来轻松解决此问题。您可以使用头文件中的extern
关键字执行此操作。这基本上使编译器注意到全局变量存在该名称。然后在一个特定的编译单元中将它们声明为非extern。然后,变量在.o
文件中被赋予空间,该空间是编译该编译单元的结果。所以基本上:
在foo.h
:
extern int width;
extern int height;
在some_random.cpp
(但可能是foo.cpp
):
#include "foo.h"
int width = 0;
int height = 0;
编译单元的概念仅与文件级(不在类,结构或函数定义内)静态变量相关。在类,结构或函数定义中声明的静态变量遵循一些不同的规则。不知何故,一旦你理解了static
的每个不同规则,它们都被称为static
真的很有意义。 : - )