The toy code is quite simple:
#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;
}
When I compile it using g++ -std=c++11 -O3 test.cpp -o test
, it passes and runs as expected; but using the intel compiler with icpc -std=c++11 -O3 test.cpp -o test
, an error occurs:
test.cpp(8): error: function call must have a constant value in a constant expression
int keys[SIZE];
Why is it regarded as a function call? But if I used simple arithmetic in the macro (e.g. #define SIZE (A / 2)
), the error disappears.
gcc version: 4.8.5; icc version: 16.0.3.
Any clue how to solve this issue? Thanks.
------------------ ADDED ------------------
If int keys[SIZE]
is declared in the main function instead of the struct, i.e. like this:
#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;
}
it will pass both gnu and intel compilers. Quite interesting and wierd. I am not sure if I made any mistake that I am not aware of, any possbile clue?
#define A 10
#define SIZE (int)(ceil(A / 2))
Your SIZE
is not a compile-time constant, because ceil
is a floating point function from <math.h>
. So the compiler is understanding the variable int keys[SIZE];
as a variable length array (VLA) (whose size is probably computed at runtime). Standard C++11 or C++14 don't have VLAs. But GCC accepts them as an extension to the language. Notice that if you declare your struct node
then keys
is not a variable but a field or member.
BTW, if you replace the define
of SIZE
with
#define SIZE ((A+1)/2)
it becomes a compile-time constant (e.g. a constexpr
in C++ parlance) and has the same value as before.
BTW, your code is not genuine C++11, but looks like C11 code. I would suggest to install a newer version of GCC (in march 2017, use GCC 6, not some old 4.8). Then use constexpr
and std::array
VLAs cannot occur as fields in struct
-s. C99 and C11 have flexible array members as the possible last member of a struct
. C++11 don't have them.
Probably, your GCC compiler (and the <math.h>
header) knows that abs
can be expanded as __builtin_abs
which is handled specially by the GCC compiler (but not by others) (so SIZE
is expanded as (int)(ceil(10 / 2))
which, with GCC specifically, becomes a compile-time constant thanks to __builtin_abs
)
You should understand that C and C++ are different languages. If you choose to code in C++ (at least C++11, anything older is obsolete in 2017) you should use its standard containers (and you probably want std::vector
since the size is runtime computed). If you choose to code in C (at least C99), consider using flexible array members and allocate your flexible structure in the heap (appropriately using malloc
or friends). Notice that C++ does not have flexible array members.
Contrarily to your title, your SIZE
is not (according to the standard specifications) a "compile-time-known array size" (but becomes one when optimized by gcc
or g++
)
An even better reason to use heap allocation (that is either std::vector
in C++, or a pointer to some struct
ending with a flexible array member, or a pointer to an array, in C) is that in practice you'll want to have a much bigger A
(e.g. #define A 100000
...) and it is not reasonable to allocate large data structures on the call stack (often limited to a megabyte or a few of them on current machines and operating systems).