18

配列を初期化する (C++ では、C で機能するソリューションはここでも機能する可能性が高い) 要素よりも少ない初期化子を使用することは完全に合法です。

int array[10] = { 1, 2, 3 };

ただし、これはあいまいなバグの原因になる可能性があります。コンパイラ (gcc) が 1 つの特定の配列の初期化子の数をチェックし、宣言されたサイズと実際のサイズが一致しない場合に警告またはエラーを発生させる方法はありますか?

私は使用できることを知ってint array[] = { 1, 2, 3 };おり、静的アサーションを使用sizeof(array)して、期待を検証することができます。しかし、私はarray他の翻訳単位で使用しているため、明示的なサイズで宣言する必要があります。したがって、このトリックは私にはうまくいきません。

4

4 に答える 4

7

(リクエストに応じてコメントから昇格)

配列内の値がシステムの正しい機能にとって重要であり、最後にゼロで初期化された値があるとバグが発生する場合は、強制しようとするのではなく、配列に正しいデータが含まれていることを確認する単体テストを追加します。コードでそれ。

于 2013-03-07T12:59:45.503 に答える
5

他の翻訳単位で使用arrayしているため、明らかに外部リンケージがあります。この場合、宣言が同じ型を与える限り、2 回宣言することができます。したがって、コンパイラが初期化子をカウントできるようにし、サイズを指定することで、2 回宣言するだけです。宣言するヘッダーの前に、この行を 1 つのソース ファイルに挿入しますarray

int array[] = { 1, 2, 3 };

同じファイルの後半に、次のような#include行で、 を宣言する行を追加しarrayます。

extern int array[10];

2 つの宣言で配列のサイズが異なる場合、コンパイラはエラーを報告します。それらが同じ場合、コンパイラはそれらを受け入れます。

于 2013-03-07T12:14:53.330 に答える
4

考えがある。

#define C_ASSERT(expr) extern char CAssertExtern[(expr)?1:-1]

#define NUM_ARGS__(X, \
                      N64,N63,N62,N61,N60, \
  N59,N58,N57,N56,N55,N54,N53,N52,N51,N50, \
  N49,N48,N47,N46,N45,N44,N43,N42,N41,N40, \
  N39,N38,N37,N36,N35,N34,N33,N32,N31,N30, \
  N29,N28,N27,N26,N25,N24,N23,N22,N21,N20, \
  N19,N18,N17,N16,N15,N14,N13,N12,N11,N10, \
  N09,N08,N07,N06,N05,N04,N03,N02,N01,  N, ...) N

#define NUM_ARGS(...) \
  NUM_ARGS__(0, __VA_ARGS__, \
                 64,63,62,61,60, \
  59,58,57,56,55,54,53,52,51,50, \
  49,48,47,46,45,44,43,42,41,40, \
  39,38,37,36,35,34,33,32,31,30, \
  29,28,27,26,25,24,23,22,21,20, \
  19,18,17,16,15,14,13,12,11,10, \
   9, 8, 7, 6, 5, 4, 3, 2, 1, 0)

#define DECL_INIT_ARRAYN(TYPE, NAME, COUNT, N, ...) \
  C_ASSERT(COUNT == N); \
  TYPE NAME[COUNT] = { __VA_ARGS__ }

#define DECL_INIT_ARRAY(TYPE, NAME, COUNT, ...) \
  DECL_INIT_ARRAYN(TYPE, NAME, COUNT, NUM_ARGS(__VA_ARGS__), __VA_ARGS__)

DECL_INIT_ARRAY(const int, array3_3, 3, 1, 2, 3);

int main(void)
{
  DECL_INIT_ARRAY(const int, array5_4, 5, 1, 2, 3, 4);
  DECL_INIT_ARRAY(const int, array5_6, 5, 1, 2, 3, 4, 5, 6);
  return 0;
}

出力 ( ideone ):

prog.c: In function ‘main’:
prog.c:33:3: error: size of array ‘CAssertExtern’ is negative
prog.c:34:3: error: size of array ‘CAssertExtern’ is negative
prog.c:34:3: error: excess elements in array initializer [-Werror]
prog.c:34:3: error: (near initialization for ‘array5_6’) [-Werror]
prog.c:34:3: error: unused variable ‘array5_6’ [-Werror=unused-variable]
prog.c:33:3: error: unused variable ‘array5_4’ [-Werror=unused-variable]
prog.c:34:3: error: unused variable ‘CAssertExtern’ [-Werror=unused-variable]
cc1: all warnings being treated as errors

UPD__VA_ARGS__ : OP は、使用の同じアイデアと静的/コンパイル時のアサーションに基づいて構築された、より短い C++11 ソリューションを見つけました。

#include <tuple>

#define DECL_INIT_ARRAY(TYPE, NAME, COUNT, ...)                         \
  static_assert(COUNT ==                                                \
    std::tuple_size<decltype(std::make_tuple(__VA_ARGS__))>::value,     \
    "Array " #NAME " should have exactly " #COUNT " initializers");     \
  TYPE NAME[COUNT] = { __VA_ARGS__ }

DECL_INIT_ARRAY(const int, array3_3, 3, 1, 2, 3);

int main(void)
{
  DECL_INIT_ARRAY(const int, array5_4, 5, 1, 2, 3, 4);
  DECL_INIT_ARRAY(const int, array5_6, 5, 1, 2, 3, 4, 5, 6);
  return 0;
}

出力 ( ideone ):

prog.cpp: In function ‘int main()’:
prog.cpp:13:3: error: static assertion failed: Array array5_4 should have exactly 5 initializers
prog.cpp:14:3: error: static assertion failed: Array array5_6 should have exactly 5 initializers
prog.cpp:14:3: error: too many initializers for ‘const int [5]’
prog.cpp:13:3: warning: unused variable ‘array5_4’ [-Wunused-variable]
prog.cpp:14:3: warning: unused variable ‘array5_6’ [-Wunused-variable]
于 2013-03-07T11:55:57.427 に答える