C ++ extern常量int用于数组大小

时间:2018-08-20 23:25:56

标签: c++ arrays const global extern

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

global.h:

.myGrid {
    display: grid;
    max-height: 350px;
    max-width: 700px;
    grid-template-rows: minmax(250px, max-content) 47px;
    grid-template-columns: 33% 67%;
    grid-template-areas: "a b" "c c";
}

.left {
    max-height: 303px;
    overflow: hidden;
    grid-area: a;
}

.right {
    grid-area: b;
}

.bottom {
    grid-area: c;
}

global.cpp:

//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
#include "global.h"
const int ARRAYSIZEX = 5;
const int ARRAYSIZEY = 2;
const int ARRAYSIZEZ = 4;

在mySomeTypeArray的声明中,编译给我三个错误。

  

错误:数组绑定不是']'令牌之前的整数常量

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

谢谢

4 个答案:

答案 0 :(得分:3)

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

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

如果要共享这些值,则需要在标头中将其声明为const intextern int不会削减。

尽管这是一个简单的例子,但实际上根本没有理由走extern的道路。只需将头文件中的值定义为常规const int

答案 1 :(得分:2)

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

虽然在某些情况下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];

答案 2 :(得分:2)

数组大小必须由整数常量表达式指定。 const int对象只有在用初始化程序声明且该初始化程序也是整数常量表达式的情况下,才能在整数常量表达式中使用。您的ARRAYSIZE...变量不满足该要求。在main中,它们被声明为没有初始化程序。您不能在ARRAYSIZE...中将main变量用作数组大小。

除非您有特殊要求将这些变量赋予外部链接,否则只需在标头中声明为(并定义)为

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

这些对象将具有内部链接,这与您的原始变体尝试执行的操作不同。

如果真的要给它们外部链接,请在标头中将它们声明为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;

答案 3 :(得分:0)

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

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

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

在C ++中,编译器的关键字extern表示变量是在“某处”定义的。编译器不知道变量的真实地址,但是通过放置关键字extern可以确保变量确实存在,并且链接器将在创建可执行文件时按其名称查找其地址。

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

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