これまでセキュリティ上の懸念からscanf関数やfopen関数などのinput 関係の関数をプログラムの記述するとC4996警告(warning)が表示されていました。
警告はただの警告なので無視してコンパイルして実行ファイルを作成できましたが、Visual Studio 2017以降ではC4996がコンパイルエラーとして扱われるようになり、scanf関数やfopen関数などC4996が発生する関数を使うとコンパイルが通らなくなりました。
たしかにscanf関数はC言語入門者が真っ先に触れることになる入力関数ですが、取り扱いが非常に難しくバッファオーバーランなどのセキュリティリスクを抱えてしまいかねない危険な関数だったりもします。
対策として新たに用意されたscanf_s関数やfopen_s関数などが用意され、それらのセキュリティが強化された関数を使えばC4996が発生しなくなりますが、C4996エラーを発生させずにscanf関数やfopen関数を使う方法も用意されています。
今回はC4996エラーを発生させずにscanf関数などを使う方法を見ていきましょう。
C4996エラーの対策方法
何も対策せずに以下のコードを実行するとC4996エラーが発生します。
#include<stdio.h>
int main()
{
int input;
int resu = scanf("%d",&input); //C4996
return 0;
}
エラーなのでビルドは完了せず実行ファイルも生成されません。上記プログラムをベースにC4996エラーを解消する方法を解説します。
C4996を無効化するdefineマクロを使う
C4996エラーはプログラムとしては間違っていなくても、scanf関数などC4996エラーの対象となる関数を記述しているだけでエラーになります。
ですが、_CRT_SECURE_NO_WARNINGS
というマクロを事前に定義しておくことでC4996エラーを無効化できます。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int input;
int resu = scanf("%d",&input);
return 0;
}
記述する際の注意点として、必ずinclude文の前に書いてください。上記コードの1行目と2行目を入れ替えてstdio.hファイルをインクルードした後に_CRT_SECURE_NO_WARNINGS
を定義するとC4996エラーは消えません。
定義するだけでいいのでマクロになにか値を設定する必要はありません。
C++ならcin(標準入力)を使う
C++が使えるならcinを使いましょう。cinならC4996エラーが発生せず安全に入力処理を実行させることができます。
#include<iostream>
using namespace std;
int main()
{
int input;
cin >> input;
return input;
}
記述もシンプルでバグが発生しづらいので、C++が使えるなら何か理由がない限りcinを使うようにしてください。
C4996エラーの無効化はやらないほうが良い
この記事で解説した方法を使えばC4996エラーを発生させないようにできますが、scanf関数・fopen関数以外でもC4996エラーは発生するため、C4996エラーを無視するようにすると「エラーが出ないけどバグが発生して強制終了するプログラム」が完成してしまう可能性があります。
エラーメッセージが表示されるバグであれば簡単に修正できますが、エラーどころか警告すら表示されないバグだと修正に時間がかかってしまいますので、できる限りC4996エラーは有効のままにしてscanf_s関数など代替できる関数を使いましょう。
C++であればcinを使うなど別の方法を採用するようにしてください。