2017-03-19 2 views
0

のためのおもちゃのコードは非常に簡単ではありません。コンパイル時知られている配列サイズ:グラムを使用してコンパイルを渡さ++が、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("%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インテルコンパイラを使用して、エラーが発生します。

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コンパイラの両方を渡します。非常に興味深く、厄介です。私は私が気づいていない間違いをしているかどうかはわかりません。

+1

CまたはC++でコーディングしていますか? 'C++'タグは疑わしいです。 –

答えて

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

ceil<math.h>から浮動小数点関数であるので、あなたのSIZEは、コンパイル時の定数ではありません。したがって、コンパイラは変数int keys[SIZE];variable length array(VLA)として理解しています(そのサイズはおそらくランタイムで計算されています)。標準C++ 11またはC++ 14にはVLAがありません。しかし、GCCはそれらを言語にextensionとして受け入れます。 struct nodeを宣言した場合、keysは変数ではなくフィールドまたはメンバであることに注意してください。あなたは

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

SIZEdefineを交換する場合

ところで、それはコンパイル時の定数となります(例えば、C++用語でconstexpr)と、前と同じ値を持っています。

ところで、あなたのコードはC++ 11の本物ではありませんが、C11コードのようです。 GCCの新しいバージョンをインストールすることをお勧めします(2017年3月、GCC 6、古い4.8では使用しないでください)。次にconstexprstd::array

struct -sのフィールドにはVLAは使用できません。 C99およびC11は、最後にメンバーであるstructとしてflexible array membersを持っています。 C++ 11にはそれらがありません。

はおそらく、あなたのGCCコンパイラ(および<math.h>ヘッダ)は、absがそのようSIZEがGCCとれ、具体的(int)(ceil(10/2))として展開されている((ただし、他の人が)GCCコンパイラによって特別に処理され__builtin_absように拡張することができることを知っています__builtin_absのおかげでコンパイル時定数になる)

CとC++は異なる言語であることを理解する必要があります。C++でコード化することを選択した場合(少なくともC++11、それより古いものは2017で廃止されています)、標準containersを使用する必要があります(サイズは実行時に計算されるため、おそらくstd::vectorが必要です)。 Cでコード化する場合(少なくともC99)、柔軟な配列メンバーを使用し、ヒープに柔軟な構造を割り当てることを検討してください(適切にはmallocまたはfriendsを使用してください)。 C++には柔軟な配列メンバーがないことに注意してください。あなたのタイトルへの逆

、あなたの SIZEはない (標準仕様に従って)である「コンパイル時知られている配列サイズ」(gccまたはg++によって最適化されたときには1になる)

アンさらに良いですヒープ割り当てを使用する理由(C++でstd::vector、または柔軟な配列メンバで終わるstructのポインタ、またはCの配列へのポインタ)は、実際にはもっと大きな値を持つことが望まれます。A (例:#define A 100000 ...)、大きなデータ構造をcall stackに割り当てることは妥当ではありません(多くの場合、メガバイト現在のマシンとオペレーティングシステム上のいくつかのもの)。

+4

そうではありません。 VLAは構造体のメンバーとしては使用できません。ここで起こっていることは、GCCが 'ceex'を' constexpr'と扱っていることです。Intelはそうではありません。 GCCとインテルの両方で動作するバージョンはインテルでVLAを使用しています。 – hvd

関連する問題