文件范围和静态浮点数

2022-01-04 00:00:00 memory static scope c++

我在我的 AI 项目中遇到了一个有趣的问题.我正在尝试格式化一些调试文本,但发生了一些奇怪的事情.这是一段代码:

I've run into an interesting problem in an AI project of mine. I'm trying to format some debug text and something strange is happening. Here's a block of code:

    float ratio = 1.0f / TIME_MOD;

TIME_MOD 是一个静态浮点数,在单独的文件中声明.这个值是根据另一个类中的用户输入修改的(我已经验证了在输入"函数范围内调试时该值已更改),但是每当我尝试在外循环中除以它时,我都会得到相同的数字.(1 除以 TIME_MOD 的初始值).

TIME_MOD is a static float, declared in a separate file. This value is modified based off of user input in another class (I have verified that the value is changed while still debugging within the scope of the "input" function), but whenever I try to divide by it in my outer loop I get the same number. (1 divided by the initial value of TIME_MOD).

我是否遗漏了有关静态变量和文件范围的内容?

Am I missing something regarding static variables and file scope?

推荐答案

我认为静态"这个词有些混淆.我们有一个关键字 static 在不同的上下文中做不同的事情,我们使用静态"这个词来命名三类存储持续时间"之一.在某些情况下,static 不控制对象的存储持续时间,而只控制链接",这可能是造成混淆的主要原因.

I think there is some confusion with the word "static". We have a keyword static that does different things in different contexts and we use the word "static" to name one of three classes of "storage durations". In some contexts static does not control the storage duration of objects but only "linkage" which is probably the main reason for the confusion.

存储持续时间是对象的属性.

A storage duration is a property of an object.

  • 具有静态存储期的对象的内存只分配一次.初始化取决于对象的类型及其定义的位置.一旦被初始化,它通常会一直保持活动状态,直到 main 的执行结束.您在全局/命名空间范围内声明和定义的对象总是具有静态存储持续时间.

  • The memory of an object with static storage duration is allocated once and once only. Initialization depends on the kind of object and where it is defined. Once it is initialized, it generally stays alive until the execution of main ends. Objects you declare and define at global/namespace scope always have a static storage duration.

具有自动存储持续时间的对象只能在函数的块内定义.当执行到达定义时创建这样的对象.这可能会发生多次(递归),从而创建多个对象.当执行离开块时,对象会自动销毁.

Objects with automatic storage duration can only be defined inside a block in functions. Such an object is created when execution reaches the definition. This can happen multiple times (recursion) which creates multiple objects. When execution leaves the block the objects are automatically destroyed.

动态分配的对象具有动态存储持续时间.在这种情况下,用户通过 new、new[]、delete、delete[] 等来控制对象的生命周期.

Dynamically allocated objects have a dynamic storage duration. In this case the user controls the life-time of the objects via new, new[], delete, delete[] etc.

内部与外部链接是关于跨翻译单元的名称可见性.如果您使用外部链接声明某些内容,则您会引入一个名称,该名称也可以在其他翻译单元中使用以引用同一实体,只要这些其他 TU 包含正确的声明(通常包含在头文件中).如果您定义了具有内部链接的内容,则无法从另一个翻译单元按名称访问它.您甚至可以定义多个同名实体(每个 TU 一个),只要与外部链接的实体不超过一个即可.

Internal vs external linkage is about visibility of names across translation units. If you declare something with external linkage you introduce a name that can be used in other translation units as well to refer to the same entity as long as those other TUs contain the proper declaration (usually contained in a header file). If you define something with internal linkage you can't access it from another translation unit by name. You can even define multiple entities with the same name (one per TU) as long as you have no more than one with external linkage.

static 的效果取决于上下文:

The effect of static depends on the context:

  • 如果您在全局/命名空间范围内声明或定义一个对象,它总是一个具有静态存储持续时间"的对象.在全局/命名空间范围内使用关键字 static 根本不会影响存储持续时间.相反,它会影响链接.它声明实体――也可能是一个函数――具有内部链接.因此,存储类说明符已被误用"来做一些完全不同的事情:强制执行内部链接.在这种情况下,它与 extern 有点相反.在 C++ 中,您可以使用匿名命名空间实现相同的效果.鼓励您更喜欢匿名命名空间而不是 static 以最小化混淆".

  • If you declare or define an object at global/namespace scope it is always an object with "static storage duration". The use of the keyword static at global/namespace scope doesn't affect the storage duration at all. Instead, it affects linkage. It declares the entity -- which might be a function as well -- to have internal linkage. So, the storage class specifier has been "misused" to do something completely different: enforce internal linkage. It's sort of the opposite of extern in this context. In C++ you can achieve the same effect with an anonymous namespace. You are encouraged to prefer anonymous namespaces over static to "minimize confusion".

static at class scope 可用于声明在类范围内具有静态存储持续时间的对象.只有一个这样的变量,而不是每个对象都有一个.

static at class scope can be used to declare objects with static storage duration in the scope of the class. There's only one such variable and not one for each object.

static 在函数作用域可用于声明静态存储持续时间延迟初始化的对象

static at function scope can be used to declare objects with static storage duration that is lazily initialized

如果您说静态变量",则不清楚您的确切含义.你指的是静态存储时长"还是内部链接"?

If you say "static variable" it's not clear what you mean exactly. Do you refer to the "static storage duration" or "internal linkage"?

如果您想在翻译单元之间共享一个全局"变量,您必须在头文件中声明它作为具有外部链接和定义的实体 恰好在一个翻译单元中.请注意,未使用关键字 static:

If you want to share a "global" variable across translation units you have to declare it in a header file as an entity with external linkage and define it in exactly one translation unit. Note that the keyword static is not used:

// 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;
}

相关文章