すべてのCプログラマーは、このよく知られたマクロを使用して、配列内の要素の数を判別できます。
#define NUM_ELEMS(a) (sizeof(a)/sizeof 0[a])
典型的なユースケースは次のとおりです。
int numbers[] = {2, 3, 5, 7, 11, 13, 17, 19};
printf("%lu\n", NUM_ELEMS(numbers)); // 8, as expected
ただし、プログラマーが配列の代わりに誤ってポインターを渡すことを防ぐものは何もありません。
int * pointer = numbers;
printf("%lu\n", NUM_ELEMS(pointer));
私のシステムでは、これは2を出力します。これは、ポインターが整数の2倍の大きさであるためです。プログラマーが誤ってポインターを渡さないようにする方法を考え、解決策を見つけました。
#define NUM_ELEMS(a) (assert((void*)&(a) == (void*)(a)), (sizeof(a)/sizeof 0[a]))
これが機能するのは、配列へのポインターが最初の要素へのポインターと同じ値であるためです。代わりにポインタを渡すと、ポインタはそれ自体へのポインタと比較されますが、これはほとんどの場合falseです。(唯一の例外は、再帰的なvoidポインター、つまり、それ自体を指すvoidポインターです。私はそれと一緒に暮らすことができます。)
配列の代わりに誤ってポインタを渡すと、実行時にエラーが発生するようになりました。
Assertion `(void*)&(pointer) == (void*)(pointer)' failed.
良い!今、私はいくつかの質問があります:
assert
カンマ式の左オペランドとしての私の使用法は有効な標準Cですか?つまり、標準ではassert
式として使用できますか?これがばかげた質問ならごめんなさい:)コンパイル時にどういうわけかチェックを行うことができますか?
int b[NUM_ELEMS(a)];
私のCコンパイラはそれがVLAだと思っています。そうでなければ彼を説得する方法はありますか?私がこれを最初に考えたのですか?もしそうなら、私は何人の処女が天国で私を待っていると期待できますか?:)