著作一覧 |
C11のAppendix Kを試してみたくて、bash on Windowsのclangで次のコードをコンパイルした。
#define __STDC_WANT_LIB_EXT1__ 1 #include <stdio.h> int main() { char tmp[80]; int n = scanf_s("%s", tmp); // => コンパイルエラーとなる if (n > 0) { puts(tmp); } }
するとscanf_sは未定義だと警告され、結局はリンクエラーとなる。
test.c:(.text+0x1e): `scanf_s' に対する定義されていない参照です
/usr/include/studio.hを見たら、確かに定義が存在しない。
まあAppendix Kはオプションだからそんなものかも知れない。
でも待て、Visual Studio 2015 - Clang with Microsoft CodeGenなら行けるのではないか? と考えた。
というのは、clang with MS CodeGenでclang用に追加されるincludeディレクトリはC:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\ClangC2\include
で、ここにはstdio.hは存在しないからだ。
つまり、stdio.hはVC++のヘッダを共通で利用することになる。
で、コンパイルすると、無事コンパイルが成功する。
……いや、コンパイルが成功するのは期待する動作ではない。
期待する動作は、VC++がそうするようにコンパイルエラーとなることだ。
VC++は上記のソースをコンパイルすると次のエラーを吐く。
test.c test.c(8): warning C4473: 'scanf_s': 書式文字列として渡された引数が不足しています test.c(8): note: プレースホルダーとそのパラメーターには 2 の可変個引数が必要ですが、1 が指定されています。 test.c(8): note: 不足している可変個引数 2 が書式文字列 '%s' に必要です test.c(8): note: この引数はバッファー サイズとして使用されます
で、予想されるように、clangでコンパイルしたプログラムは実行できて、かつ動作は予想できない。バッファサイズを与えていないから何文字入力できるか不明だし、とりあえず山ほど入力すれば0xC0000005で死ぬ。
これはちょっとひどいのではないか? まだ、scanf_sは未定義といって怒るほうが1000億倍ましだ。
もちろん以下のように書き直すと、期待通りに動作する。
#define __STDC_WANT_LIB_EXT1__ 1 // <= これ結局本当におまじない以上の意味が無いということだな #include <stdio.h> int main() { char tmp[80]; int n = scanf_s("%s", tmp, (unsigned)sizeof(tmp)); // x64でも通るようにするには(unsigned)キャストが必要(size_tではない) if (n > 0) { puts(tmp); } }
ジェズイットを見習え |