我在我的AI项目中遇到了一个有趣的问题。我正在尝试格式化一些调试文本,并且发生了一些奇怪的事情。这是一段代码:
float ratio = 1.0f / TIME_MOD;
TIME_MOD是一个静态浮点数,在单独的文件中声明。这个值是基于另一个类中的用户输入修改的(我已经验证了值在“input”函数的范围内仍在调试时被更改),但每当我尝试在外部循环中除以它时,我得到了相同的号码。 (1除以TIME_MOD的初始值)。
我是否遗漏了有关静态变量和文件范围的内容?
答案 0 :(得分:15)
我认为与“静态”这个词有些混淆。我们有一个关键字static
在不同的上下文中执行不同的操作,我们使用“静态”一词来命名三个“存储持续时间”类别中的一个。在某些情况下,static
不控制对象的存储持续时间,而只控制“链接”,这可能是导致混淆的主要原因。
存储持续时间是对象的属性。
具有静态存储持续时间的对象的内存仅分配一次。初始化取决于对象的类型和定义的位置。一旦初始化,它通常会保持活着,直到执行主要结束。您在全局/命名空间范围内声明和定义的对象始终具有静态存储持续时间。
自动存储持续时间的对象只能在函数块中定义。执行到达定义时会创建这样的对象。这可能会多次发生(递归),从而创建多个对象。当执行离开块时,对象会自动销毁。
动态分配的对象具有动态存储持续时间。在这种情况下,用户通过new,new [],delete,delete []等来控制对象的生命周期。
内部与外部联系是关于翻译单位的名称的可见性。如果您使用外部链接声明某些内容,则引入一个名称,该名称可以在其他翻译单元中使用,只要这些其他TU包含正确的声明(通常包含在头文件中),就可以引用同一实体。如果您使用内部链接定义某些内容,则无法通过名称从另一个翻译单元访问它。您甚至可以定义多个具有相同名称的实体(每个TU一个),只要您的外部链接不超过一个。
static
的效果取决于具体情况:
如果在全局/命名空间范围内声明或定义对象,则总是具有“静态存储持续时间”的对象。在全局/命名空间范围内使用关键字static
根本不会影响存储持续时间。相反,它会影响联系。它声明实体 - 也可能是一个函数 - 具有内部链接。因此,存储类说明符被“误用”以完成不同的操作:强制执行内部链接。在这种情况下,它与extern
相反。在C ++中,您可以使用匿名命名空间实现相同的效果。我们鼓励您优先使用static
之上的匿名命名空间来“尽量减少混淆”。
static
可用于在类的范围内声明具有静态存储持续时间的对象。每个对象只有一个这样的变量而不是一个。
static
可用于声明具有懒惰初始化的静态存储持续时间的对象
如果你说“静态变量”,那么你的意思并不清楚。您是指“静态存储持续时间”还是“内部链接”?
如果要跨翻译单元共享“全局”变量,则必须在头文件中声明作为具有外部链接且定义的实体它恰好在一个翻译单元中。请注意,未使用关键字static
:
// myheader.hpp
extern int k; // declaring an int variable with external linkage
// foo.cpp
#include "myheader.hpp"
int k; // defining an int variable with external linkage
// bar.cpp
#include "myheader.hpp"
int main() {
return k;
}
答案 1 :(得分:2)
静态变量仅存在于当前编译单元中。从定义中删除静态并将其更改为“volatile”(虽然这假设您使用多个线程,否则您不需要使用volatile)并且一切都应该没问题。
编辑:在这里你的回答我假设你有一些代码如下。
A.cpp:
static float TIME_MOD = <some value>;
B.CPP:
static float TIME_MOD = <some value>;
如果你这样做,那么TIME_MOD存在于2个地方,这就是问题的根源。你需要更像这样重写代码。
A.cpp:
float TIME_MOD = <some value>;
B.CPP(和C.CPP,D.CPP等):
extern float TIME_MOD;
然后像往常一样使用TIME_MOD。这告诉编译器TIME_MOD在其他地方,而不用担心不知道它包含什么。然后链接器将通过并将此浮动TIME_MOD定义“链接”到正确的定义。
它还值得指出,它可能有“外部浮动TIME_MOD;”在某个头文件中,并将其包含在您需要的任何CPP文件中。仍然将实际定义(即非外部定义)保存在一个文件中,而且只保留一个文件。
这肯定会解释我认为你是一个静态的东西(我认为这是不可能的)。
答案 2 :(得分:0)
您可以将静态变量更改为#define,并将单个成员变量设置为等于它。修改和访问将适用于单例的成员变量。
答案 3 :(得分:0)
静态变量在内部链接。您无法访问其他源文件中定义的静态变量 如果在某个头文件中定义了静态变量TIME_MOD,则可能会出现这种情况。在输入和比率源文件中包含相同的头文件,因此两个文件都有变量TIME_MOD的私有副本,<登记/> 现在输入模块更改了TIME_MOD值,但它修改了自己的私有副本,因此ratio文件中的值保持不变,从而保持您的行为。
现在,如果是这种情况,您不需要静态TIME_MOD,并且为了解决名称冲突,您可能希望使用名称空间。
答案 4 :(得分:0)
我猜你在头文件中将此变量声明为:static float TIME_MOD; 并将此文件包含在cpps中。通过这样做,您可以在每个编译单元中有效地创建相同命名变量的单独实例。 您应该将声明更改为:extern float TIME_MOD; 并在一个cpps中定义变量:float TIME_MOD = 0;