编译时已知的数组大小:使用 G++ 传递编译,但不适用于 ICPC
compile-time-known array size: passed compilation using g++ but not for icpc
玩具代码非常简单:
#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 node
则keys
不是变量,而是字段或成员。
顺便说一句,如果您将SIZE
的define
替换为
#define SIZE ((A+1)/2)
它成为一个编译时常量(例如C++的说法是constexpr
),并且具有与以前相同的值。
顺便说一句,您的代码不是正版 C++11,但看起来像 C11 代码。我建议安装较新版本的 GCC(在 2017 年 3 月,使用 GCC 6,而不是一些旧的 4.8)。然后使用constexpr
和std::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
不是(根据标准规范)"编译时已知的数组大小"(但当通过gcc
或g++
进行优化时会变成一个)
使用堆分配(即在 C++ 中std::vector
,或者指向以灵活数组成员结尾的某些struct
的指针,或指向数组的指针,在 C 中)的一个更好的理由是,在实践中,您需要更大的A
(例如#define A 100000
...在调用堆栈上分配大型数据结构是不合理的(在当前机器和操作系统上通常限制为兆字节或几个