c++中的静态全局变量

Static global variables in C++

本文关键字:全局变量 静态 c++      更新时间:2023-10-16

我想通过malloc方法创建一个整数数组。我希望这个数组是全局的,可以在程序的任何地方使用。我把代码放在一个头文件中,看起来像这样:

static int *pieces;

然后我有一个函数用我想要的数字填充它。该函数位于名称空间中,该名称空间在其自己的.cpp文件中实现。但是,我将头文件导入到main.c中,并从创建数组的名称空间调用函数,如:

pieces = malloc(sizeof(int) * 128);

但是当我试图在main中访问数组中的数字时(在调用创建数组的函数之后),它崩溃了,并说碎片没有初始化。但是在这个函数中,我可以创建它并对其中的数字进行操作。我的印象是,通过使片段成为静态变量,每当某个函数在任何地方改变(或设置它),那么这将影响变量在任何地方的使用。基本上,我想说的是为什么在main中piece没有设置,即使我在一个函数中设置了它?

Static是一个具有多种含义的关键字,在这种特殊情况下,它表示而不是全局(释义)

这意味着每个 .cpp文件都有自己的变量副本。因此,当您在main.cpp中初始化时,只在main.cpp 中初始化。其他文件仍然未初始化。

解决这个问题的第一件事是删除关键字static。这将导致"多重定义问题"。要解决这个问题,你应该在.cpp文件中定义变量,并在头文件中extern声明它。
编辑:你只是分配内存给它,不算作初始化。您需要在分配后将内存初始化为0。

您可以使用new int[128]()而不是更详细的malloc语法,这也将执行初始化?或者你也可以选择简单的方法(这就是它的作用),使用std::vector

关键是:

static int *pieces;

你说你把它放在标题里了。这不是导出符号的方法。任何包含头文件的文件都将获得自己的未初始化指针pieces的静态版本。

相反,你把这个放在标题中:

extern int *pieces;
extern int init_pieces();

在源文件中,这样做:

static const size_t num_pieces = 128;
int *pieces = 0;
int init_pieces()
{
    pieces = malloc( num_pieces * sizeof(int) );
    return pieces != NULL;
}

现在,当您包含您的头文件时,您的源文件将知道从其他地方获得pieces,并将等待链接器确定在哪里。我还建议为数组设置一个"init"函数。但是,我并没有添加一个"释放"函数。

注意这都是C,而不是c++。如果你正在使用c++,你应该使用new,或者更好的是,使用vector

另外,在c++中使用静态值时,请注意:c++静态初始化顺序

在c++ 17标准中,您可以使用inline说明符来代替static。对于变量,这意味着每个对象单元都有变量的副本,但链接器只选择其中一个。或者,如cppreference所述:

内联函数或内联变量(c++ 17起)具有以下内容属性:

1)内联可以有多个定义函数或变量(自c++ 17起)在程序中只要每个定义出现在不同的翻译单元和(对于非静态)内联函数和变量(自c++ 17起))的所有定义都是相同的。例如,内联函数或内联变量(自c++ 17起)可以在#include的头文件中定义多个源文件。

2)内联函数或的定义变量(自c++ 17起)必须出现在翻译单元中它被访问(不一定在访问点之前)。

3)具有外部链接的内联函数或变量(自c++ 17起)。未声明为static)具有以下附加属性:

1) It must be declared inline in every translation unit.
2) It has the same address in every translation unit.

支持在(源):

  • MSVC自19.12版本(VS 2017 15.5)
  • GCC 7
  • 叮当声3.9
  • ICC 18.0

在这种情况下,它意味着你可以替换

static int *pieces;

inline int *pieces;

对于各种体系结构上的高性能代码,您可能需要malloc-y分配而不是通用的new。这是因为您将使用mymalloc()之类的东西包装它,然后使用与体系结构相关的函数,例如实现适当对齐以避免缓存丢失的函数,并执行硬件制造商(如IBM (Bluegene)或Intel (MIC))提供的其他漂亮功能。所有这些优化的分配例程都具有malloc类型框架。