さて、きのうclを使っていろいろコンパイルしてたのですが、変なwarningが出たという話です。
clというのはMicrosoftのVisual StudioのC++のコンパイラです。
CompileとLinkの頭文字を取ったもので、名前は特にCとは関係ない。
それはよいのですが、こんなプログラムを書きました。
#include <stdio.h>
main(){
int in;
if ( fscanf(stdin,"%d",&in) != 1 )
abort();
fprintf(stdout,"%d\n",in);
return 0;
}
まぁわりとうまいこと行ってるプログラムだと思います。
ちゃんと読み取り失敗して、読み取り成功した数が1でなければabortでとりあえず待避させているし。
ところがclは
「warning C4996: ‘fscanf’ が古い形式として宣言されました。」
とおっしゃる。けどfscanfって今も昔もこれだと思うのだが。
と思って調べると、Microsoftはchar[]型やらのメモリ破壊対策を行ったらしい。
getsの代わりにgets_s、scanf , fscanf , sscanfの代わりにscanf_s , fscanf_s , sscanf_sを使えと。
gets_sの方はfgetsを使えば同じ事ができる。
fgets(str,10,stdin);
gets_s(str,10);
こんな風に配列の大きさを書き添えろと。確かにfgetsで十分。
改行コードの取り扱いは調べてないからわからない、fgetsでいいやと思ったから。
そうそう、これに関連してだが、このように読み取りの上限を定めると読み残しが発生する。
で、fgetsを使うときは
fgets(str,10,stdin);
l=strlen(str);
if (str[l-1] != '\n')
abort();
随分極端な処理だが…
strlenでchar[]の文字列の長さを調べる。strlenはstring.hに収録されてる。
strlenで調べた長さにはNULL文字は含まないので、この場合は0〜9の値を取るだろう。
ここで9文字と出てきたとする。そのときstr[l-1]、すなわち最後の文字の値を確認する。
でstr[8]の値を確認して’\n’なら問題ない。fgetsは改行まで読み取るので、
正常に1行読み取れれば最後には’\n’があるはず。
しかしこれがないとき、正常に行の最後まで読み取れていない。
その場合の処理の仕方はいろいろあって、動的にメモリを拡張するとかあるのだが、今回はもうabortで待避している。
元に戻って、scanf関係は、%c、%sを使うときに関係ある。
どちらもメモリ破壊防止には、%1cやら%19cやら長さをフォーマットで指定すればいい。
char型に%4cを放り込んだり、20しか確保してないchar[]に19文字を越える文字をいれることはできないはずということ。
そのfscanf_sなどでは、%c、%sなどを使うときには、大きさを受け取る方に大きさを指定することになっている。
まぁけどあまり関係なさそうなので無視。
で、これを無視するためには1行目に
#define _CRT_SECURE_NO_DEPRECATE
と書けばいい。
clでガリガリコンパイルするのは初めてな気もするのだが、abortが実行されるとデバッグするかと聞かれる。
なんか大げさだな。まぁabortにもいろいろな使い方があると思うが、今回はこれでいいことにしよう。
それにしてもcl使って改めて感じるが、Borland C++ Compilerのコンパイルはすごく速いなぁ。
まぁ今のコンピュータでコンパイル速度なんて議論する必要はない気もするが、
気分はいいね。