2019年6月2日日曜日

C言語で仮引数の配列サイズは無視される

結論はタイトルの通りなんだけど、久々にサイズ付き配列を仮引数にしたコードを見かけてギョッとしたことがあったので、改めて調べてみた。

まず、以下のような仮引数自体は、文法的には一応NGではない。

void test(const char arg[32]) {
    printf("sizeof(arg) : %lu, arg : %s\n", sizeof(arg), arg);
}
ただ、決して配列を値渡ししているわけではない。ポインタや参照渡しを理解していない学生レベルの人が書きがちなコードなので、稀に仕事で見かけるとギョッとするのだろう。

さて、では、上記の例の32はどんな意味を持つのかというと、改めてタイトルの通り無視される。手元のApple LLVM version 10.0.1 (clang-1001.0.46.4)でサクッとコンパイルしてみると、実行するまでもなくwarningを吐いてくれた。

test_arg.c:4:51: warning: sizeof on array function parameter will return size of
      'const char *' instead of 'const char [32]' [-Wsizeof-array-argument]
    printf("sizeof(arg) : %lu, arg : %s\n", sizeof(arg), arg);
要するに、32だろうが256だろうがconst char *と書いたのと同様に解釈される。配列っぽく記述していてもコンパイラはポインタとして扱うので、配列の要素数という情報は捨てられる。sizeof(arg)は32ではなく、アドレスを表現するのに必要なサイズ(環境によるけど、8とか4)になるのだ。

やっぱり、サイズ情報を渡しているかのように誤解させる記述は、やめたほうがいいだろうね。…と言うわけで、ただ見慣れないという理由で頭ごなしに否定するのではなく、誤解の元になるから修正しろと言うのがスマートだろう。

0 件のコメント:

コメントを投稿