fopen_sってなんだよ(C言語)
☆お知らせ☆
この記事が人気すぎるので真面目にfopen_sについて新しい記事を書いたのでご覧ください。
https://khws4v1.myhome.cx/article/2017/04/13/%e3%81%aa%e3%82%93%e3%81%8b%e4%ba%ba%e6%b0%97%e3%81%aefopen_s%e9%96%a2%e6%95%b0%e3%81%ab%e3%81%a4%e3%81%84%e3%81%a6/
ファイル操作?簡単っていうwwwwwwww
こんなのできて当たり前っていうwwwwwwww
って何?fopen
じゃなくてfopen_s
を使え?
fopen_s
って何?初めて聞くんだけど・・・。
違い
fopen
とfopen_s
との違い、なんかセキュリティが強化されているとか説明を受けましたがなんのこっちゃさっぱりなので自力で調べることに。
fopen
はほとんどの環境で使えますが、fopen_s
はC11以降で標準ライブラリに導入された関数です。
これらの関数は戻り値と引数が異なります。
1 |
FILE *fopen( const char *restrict filename, const char *restrict mode ); |
1 2 3 |
errno_t fopen_s(FILE *restrict *restrict streamptr, const char *restrict filename, const char *restrict mode); |
http://en.cppreference.com/w/c/io/fopen
戻り値がfopen
はFILE *
、fopen_s
はerrno_t
になっています。
fopen_s
は戻り値がerrno_t
なので、いちいちerrno
からエラーの原因を調べなくても良くなっています。
また、fopen_s
でファイルを開くと他のアプリケーションから開けなくなります。
なぜfopen_sなのか
大学の授業ではC89基準のコードしか教えていなかったのに突然教科書に無いC11で導入されたfopen_s
をセキュリティを理由に出してきました。
でもセキュリティをそんなに気にするならscanf
とかのバッファオーバランという遥かに深刻な問題をほったらかしにするはずないです。
それに同類のfprintf_s
やfscanf_s
などは出ていません。
MSVC 2012はC99には対応しておらず、それなのにC11で導入された関数を使わせるなぜなのか?
その前にC89・C99の時点では非標準の関数を標準の関数として使わせるのはなぜなのか?
ちなみにgccとclangでは最新バージョンでもfopen_s
は使えません。
そしてその謎を解明するべくおもむろにMSVC 2013で適当なコードをコンパイルしてみることに。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include <stdio.h> #define FILE_NAME "C:\Users\User\Documents\Visual Studio 2013\Projects\hello.txt" int main(void) { FILE *fp; char buff[1000]; if ((fp = fopen(FILE_NAME, "r"))) { fscanf(fp, "%s", buff); printf("%sn", buff); fclose(fp); } else { return -1; } return 0; } |
結果は・・・
fopen_s
使えと言われてコンパイルできませんでした。
C89・C99では非標準の関数をわざわざ使わせたのはセキュリティではなくコンパイルエラーを回避するためだったわけですね。
個人的にはこの仕様とこの対処法は嫌いですけど・・・。
Visual Studio 2005で、_s 関数は導入されました。当時は_sでない関数を使った場合は警告でした。これはセキュリティのためで、当時はマイクロソフト社の独自拡張の関数でした。ところが時代も進み、世間的にもセキュリティ問題が関心ごとになり、C/C++の標準として取り入れるべく、TR 24731-1 として標準化委員会で審議され、C11で標準化(規格書のAnnex K. Bounds-checking interfaces)に至りました。おそらく、それを受けてマイクロソフト社もVisual Studioの設定を変えて、_sでない関数を使用するとデフォルトではエラーになるようになったのです。