【问题标题】:compile-time-known array size: passed compilation using g++ but not for icpc编译时已知数组大小:使用 g++ 传递编译,但不用于 icpc
【发布时间】:2017-03-19 06:43:20
【问题描述】:

玩具代码很简单:

#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("%d\n", a_node.keys[i]);
    }
    return 0;
}

当我使用g++ -std=c++11 -O3 test.cpp -o test 编译它时,它按预期通过并运行;但是使用带有icpc -std=c++11 -O3 test.cpp -o test的intel编译器,会出现错误:

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。

任何线索如何解决这个问题?谢谢。

----------------- 已添加------------------

如果 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("%d\n", keys[i]);
    }
    return 0;
}

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

【问题讨论】:

  • 你是用 C 还是 C++ 编码? c++ 标签是可疑的。

标签: c++ arrays gcc struct icc


【解决方案1】:
#define A 10
#define SIZE (int)(ceil(A / 2))

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

顺便说一句,如果您将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 将 flexible array members 作为 struct 的可能 last 成员。 C++11 没有。

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

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

与您的标题相反,您的 SIZE 不是(根据标准规范)“编译时已知数组大小”(但在通过 gcc 或 @ 优化时变为一个987654357@)

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

【讨论】:

  • 这不太对。 VLA 不能作为结构的成员出现。这里发生的情况是 GCC 将 ceil 视为 constexpr,而英特尔则没有。不过,在 GCC 和 Intel 上都可以使用的版本在 Intel 上使用 VLA。
猜你喜欢
  • 2012-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多