ARRAY_SIZE
Linux カーネルは、この問題に対処するためにの優れた実装を使用します。
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
と
#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
と
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
もちろん、これは GNU C でのみ移植可能です
。これは、typeof
演算子と__builtin_types_compatible_p
関数の 2 つの組み込み関数を使用するためです。BUILD_BUG_ON_ZERO
また、GNU C でのみ有効な「有名な」マクロを使用します。
コンパイル時の評価要件 (私たちが望んでいること) を想定すると、このマクロの移植可能な実装はわかりません。
「セミポータブル」実装 (すべてのケースをカバーするわけではありません) は次のとおりです。
#define ARRAY_SIZE(arr) \
(sizeof(arr) / sizeof((arr)[0]) + STATIC_EXP(IS_ARRAY(arr)))
と
#define IS_ARRAY(arr) ((void*)&(arr) == &(arr)[0])
#define STATIC_EXP(e) \
(0 * sizeof (struct { int ARRAY_SIZE_FAILED:(2 * (e) - 1);}))
これによりgcc
、引数が配列の場合は警告が表示されません-std=c99 -Wall
が-pedantic
、警告が表示されます。その理由はIS_ARRAY
、式が整数定数式ではなく (ポインター型へのキャストと添字演算子は整数定数式では許可されていません)、ビットフィールド幅にSTATIC_EXP
は整数定数式が必要であるためです。