编译时已知的数组大小:使用 G++ 传递编译,但不适用于 ICPC

compile-time-known array size: passed compilation using g++ but not for icpc

本文关键字:编译 ICPC 适用于 不适用 G++ 数组 使用      更新时间:2023-10-16

玩具代码非常简单:

#include <stdio.h>
#include <math.h>
#define A 10
#define SIZE (int)(ceil(A / 2)) // needs computation but known at compile-time
struct node {
int keys[SIZE];
};
int main() {
node a_node;
for (int i = 0; i < SIZE; ++i) {
a_node.keys[i] = i;
printf("%dn", a_node.keys[i]);
}
return 0;
}

当我使用g++ -std=c++11 -O3 test.cpp -o test编译它时,它会按预期传递和运行;但是使用带有icpc -std=c++11 -O3 test.cpp -o test的英特尔编译器时,会发生错误:

test.cpp(8): error: function call must have a constant value in a constant expression int keys[SIZE];

为什么它被视为函数调用?但是如果我在宏中使用简单的算术(例如#define SIZE (A / 2)),错误消失。

GCC 版本:4.8.5;ICC 版本:16.0.3。

有什么线索可以解决这个问题吗?谢谢。

------------------添加------------------

如果在 main 函数而不是结构中声明int keys[SIZE],即像这样:

#include <stdio.h>
#include <math.h>
#define A 10
#define SIZE (int)(ceil(A / 2))
/*struct node {
int keys[SIZE];
};*/
int main() {
//node a_node;
int keys[SIZE];
for (int i = 0; i < SIZE; ++i) {
keys[i] = i;
printf("%dn", keys[i]);
}
return 0;
}

它将通过GNU和Intel编译器。相当有趣和奇怪。我不确定我是否犯了任何我不知道的错误,任何可能的线索?

#define A 10
#define SIZE (int)(ceil(A / 2))

您的SIZE不是编译时常量,因为ceil是来自<math.h>的浮点函数。因此,编译器将变量int keys[SIZE];理解为可变长度数组 (VLA)(其大小可能在运行时计算)。标准 C++11 或 C++14 没有 VLA。但是GCC接受它们作为语言的扩展。请注意,如果声明struct nodekeys不是变量,而是字段或成员。

顺便说一句,如果您将SIZEdefine替换为

#define SIZE ((A+1)/2)

它成为一个编译时常量(例如C++的说法是constexpr),并且具有与以前相同的值。

顺便说一句,您的代码不是正版 C++11,但看起来像 C11 代码。我建议安装较新版本的 GCC(在 2017 年 3 月,使用 GCC 6,而不是一些旧的 4.8)。然后使用constexprstd::array

VLA 不能作为struct-s 中的字段出现。C99 和 C11 具有灵活的数组成员作为struct最后一个成员。C++11没有它们。

可能,您的 GCC 编译器(和<math.h>标头)知道abs可以扩展为__builtin_abs,这是由 GCC 编译器(但不是由其他人)专门处理的(因此SIZE扩展为(int)(ceil(10 / 2)),特别是 GCC,由于__builtin_abs而成为编译时常量)

您应该了解 C 和 C++ 是不同的语言。如果你选择在C++编码(至少C++11,任何较旧的在2017年都已经过时了),你应该使用它的标准容器(你可能想要std::vector,因为大小是运行时计算的)。如果选择使用 C(至少为 C99)编写代码,请考虑使用灵活的数组成员并在堆中分配灵活的结构(适当地使用malloc或 friends)。请注意,C++没有灵活的数组成员。

与您的标题相反,您的SIZE不是(根据标准规范)"编译时已知的数组大小"(但当通过gccg++进行优化时会变成一个)

使用堆分配(即在 C++ 中std::vector,或者指向以灵活数组成员结尾的某些struct的指针,或指向数组的指针,在 C 中)的一个更好的理由是,在实践中,您需要更大的A(例如#define A 100000...在调用堆栈上分配大型数据结构是不合理的(在当前机器和操作系统上通常限制为兆字节或几个

)。