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 int
。 extern 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;
这里的问题是ARRAYSIZEX
、ARRAYSIZEY
和ARRAYSIZEZ
不是编译时常量。它们是常量 - 因此它们的值无法更改,但编译器不知道它们的值。
在 C++ 中,编译过程包含 3 个基本步骤。
- 预处理器完成所有源文件的预处理。
- 编译器对每个翻译单元(.cpp 文件)进行编译。对于每个翻译单元,编译器都会创建一个目标文件。
- 链接器完成所有目标文件的链接。输出是一个可执行文件。
在 C++ 中,编译器的关键字 extern
意味着变量是 'somewhere' 定义的。编译器不知道变量的真实地址,但通过放置关键字 extern
可以确保变量确实存在,并且链接器可以在创建可执行文件时通过名称找到它的地址。
这里的问题是第 2 步中的编译器想要创建目标文件,但它不知道数组有多大,因为它不知道这些常量的值。是的,第 3 步中的链接器在将所有目标文件放在一起时最终会找到它们,但对编译器来说为时已晚。所以它会产生那个错误。
解决方法很简单。使用已经提到的 constexpr
关键字并使用初始化器初始化所有变量。关键字 constexpr
标记编译时常量 - 必须在初始化程序中初始化并且编译器已知的常量。
我的代码中有以下三个文件(删除了大部分代码。这只是为了隔离问题)。
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 int
。 extern 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;
这里的问题是ARRAYSIZEX
、ARRAYSIZEY
和ARRAYSIZEZ
不是编译时常量。它们是常量 - 因此它们的值无法更改,但编译器不知道它们的值。
在 C++ 中,编译过程包含 3 个基本步骤。
- 预处理器完成所有源文件的预处理。
- 编译器对每个翻译单元(.cpp 文件)进行编译。对于每个翻译单元,编译器都会创建一个目标文件。
- 链接器完成所有目标文件的链接。输出是一个可执行文件。
在 C++ 中,编译器的关键字 extern
意味着变量是 'somewhere' 定义的。编译器不知道变量的真实地址,但通过放置关键字 extern
可以确保变量确实存在,并且链接器可以在创建可执行文件时通过名称找到它的地址。
这里的问题是第 2 步中的编译器想要创建目标文件,但它不知道数组有多大,因为它不知道这些常量的值。是的,第 3 步中的链接器在将所有目标文件放在一起时最终会找到它们,但对编译器来说为时已晚。所以它会产生那个错误。
解决方法很简单。使用已经提到的 constexpr
关键字并使用初始化器初始化所有变量。关键字 constexpr
标记编译时常量 - 必须在初始化程序中初始化并且编译器已知的常量。