c++ extern constant int 用于数组大小

c++ extern constant int for array size

我的代码中有以下三个文件(删除了大部分代码。这只是为了隔离问题)。

global.h:

//global.h
#ifndef GLOBAL_H
#define GLOBAL_H
extern const int ARRAYSIZEX;
extern const int ARRAYSIZEY;
extern const int ARRAYSIZEZ;
#endif //GLOBAL_H

global.cpp:

//global.cpp
#include "global.h"
const int ARRAYSIZEX = 5;
const int ARRAYSIZEY = 2;
const int ARRAYSIZEZ = 4;

主要内容:

//main
#include "global.h"
using namespace std;

someType mySomeTypeArray[ARRAYSIZEX][ARRAYSIZEY][ARRAYSIZEZ];

int main(int argc, char **argv)
{
//...
}

编译在 mySomeTypeArray 的声明处出现三个错误。

error: array bound is not an integer constant before ']' token

我想在全局中保留我的全局变量和数组大小定义。h/cpp 对于这个应用程序,只是为了组织,以便我所有的配置参数都在一个地方。实现我想要做的事情的正确方法是什么?

谢谢

这里的问题是 extern int x 意思是“x 是在另一个文件中定义的,但是不用担心细节,你只需要知道它是一个 int” .这通常已经足够好了,除非编译器需要立即知道 x 是什么。

因为它是在整个其他文件中定义的,所以不能。该文件必须在它知道之前被编译,并且由于 C++ 的工作方式,该编译的结果不会影响该文件的编译。

如果您想共享这些值,则需要在 header 中将其声明为 const intextern int 不会剪的。

虽然这是一个微不足道的例子,但确实没有理由走 extern 这条路。只需将 header 文件中的值定义为常规 const int.

你的声明失败了,因为数组大小需要在编译时计算,而你的封装方案实际上对编译器隐藏了值。这是真的,因为编译器在单个翻译单元上工作。在编译 main.cpp 时,由于 include 语句,您的编译器只能看到 extern const int ARRAYSIZEX,但看不到在单独的翻译单元中可见的值,因此它无法弄清楚内存布局。

虽然 const 变量在某些情况下可以用作数组大小,但该语言提供了更合适的 constexpr 限定符,它带有一组限制,强制执行其编译时评估和适用性数组大小。我建议始终在适当的时候使用它,因为它会在这种情况下指出错误。在这种情况下,您会收到编译器错误,因为 extern constexpr 声明格式不正确,这暗示了正确的解决方案:将编译时常量的值直接保存在头文件中。

global.h

constexpr int ARRAYSIZEX = ...;
constexpr int ARRAYSIZEY = ...;
constexpr int ARRAYSIZEZ = ...;

main.cpp

#include "global.h"
someType mySomeTypeArray[ARRAYSIZEX][ARRAYSIZEY][ARRAYSIZEZ];

数组大小必须由整数常量表达式指定。 const int object 可以在整型常量表达式中使用,当且仅当它用初始化器声明并且该初始化器也是整型常量表达式时。您的 ARRAYSIZE... 变量不满足该要求。在 main 中,它们在没有初始化器的情况下被声明。您不能在 main.

中使用 ARRAYSIZE... 变量作为数组大小

除非您有特定要求为这些变量提供外部链接,否则只需在 header 中将它们声明(并定义)为

const int ARRAYSIZEX = 5;
const int ARRAYSIZEY = 2;
const int ARRAYSIZEZ = 4;

这些 object 将具有内部链接,这与您的原始变体试图做的不同。

如果真的想给他们外部链接,在header

中声明为inline extern const
inline extern const int ARRAYSIZEX = 5;
inline extern const int ARRAYSIZEY = 2;
inline extern const int ARRAYSIZEZ = 4;

由于 inline 本身阻止 const 强加内部链接,因此 extern 在这些声明中完全是可选的。并且由于 inline const 组合可以替换为 constexpr(如评论中指出的@M.M),您只需使用

即可达到相同的效果
constexpr int ARRAYSIZEX = 5;
constexpr int ARRAYSIZEY = 2;
constexpr int ARRAYSIZEZ = 4;

这里的问题是ARRAYSIZEXARRAYSIZEYARRAYSIZEZ不是编译时常量。它们是常量 - 因此它们的值无法更改,但编译器不知道它们的值。

在 C++ 中,编译过程包含 3 个基本步骤。

  1. 预处理器完成所有源文件的预处理。
  2. 编译器对每个翻译单元(.cpp 文件)进行编译。对于每个翻译单元,编译器都会创建一个目标文件。
  3. 链接器完成所有目标文件的链接。输出是一个可执行文件。

在 C++ 中,编译器的关键字 extern 意味着变量是 'somewhere' 定义的。编译器不知道变量的真实地址,但通过放置关键字 extern 可以确保变量确实存在,并且链接器可以在创建可执行文件时通过名称找到它的地址。

这里的问题是第 2 步中的编译器想要创建目标文件,但它不知道数组有多大,因为它不知道这些常量的值。是的,第 3 步中的链接器在将所有目标文件放在一起时最终会找到它们,但对编译器来说为时已晚。所以它会产生那个错误。

解决方法很简单。使用已经提到的 constexpr 关键字并使用初始化器初始化所有变量。关键字 constexpr 标记编译时常量 - 必须在初始化程序中初始化并且编译器已知的常量。