VisualC++ 2013 について

このエントリーをはてなブックマークに追加

VisualC++ 2013 についての情報です。

基本情報

当サイトで扱っている VisualC++ 2013 は、「VisualStudio Express 2013 for Windows Desktop」です。 これは誰しもが無料でダウンロード&インストールすることができますが、最も機能の少ないエディションです。

この他、現在では、「Visual Studio Community 2013」という新しいエディションが加わっており、 こちらは条件に合っていれば、無料で使用できます。 詳細は、マイクロソフト社の Webサイトを参照して下さい。
上記の Express Edition と違い、Windows のデスクトップ向け以外のアプリ開発の機能も統合されています。

コンパイラとしては変わりは無いので、当サイトとしては引き続き、利用者の制限が無い Express Edition で動作確認を行っています。 次期バージョン (2015?) からは、Express Edition は無くなる予定になっているので、 特に条件的に問題が無ければ、Visual Studio Community 2013 を選ぶのが良いと思います。

いずれのエディションであっても、以下の場所からダウンロードできます。

VisualC++ 2013 は、Windows 7 ~ Windows 8 の各バージョンの Windows にインストールできます。 Windows Vista以前の Windows を利用している方は、VisualC++ 2010 を選択することになります。

インストール方法については、以下のサイトを参考にして下さい。

VisualC++ 2013 のC言語への対応状況は、正式には C89規格までで(ほぼ C95対応と考えて良いかと思われます)、 C99規格の機能の多くがサポートされています。 これは、C++11 の対応が進んでおり、C++11 が C99 を内包しているためだと思われます。
C++ については、C++03規格に対応しており、C++11規格への対応度合いも上がってきています

SDLチェック

VisualC++ 2012 で、SDL (Security Development Lifecycle) チェックという機能が追加されています。 これは、新規プロジェクトを作成する際、「Win32 アプリケーションウィザード」の「アプリケーションの設定」のところで設定できます。 デフォルトではチェックが入っています。

SDLチェックの設定画面

SDLチェックが有効になっていると、strcpy関数など、セキュリティ上の問題を抱えている旧式の関数を使用したプログラムをビルドする際、 エラーとして報告されるようになります。 無効にしていると、従来 (VisualC++ 2010以前)と同様、警告が出るだけの挙動になります。

なお、この設定は、プロジェクトを作った後でも、[プロパティ] → [構成プロパティ] → [C/C++] → [SDL チェック] の項目で変更できます。

C言語を使う場合

C言語のソースファイルは、拡張子を「.c」にして下さい。

VisualC++内で、「新しい項目の追加」からソースファイルを作成する場合、 作成するファイルの名前に、デフォルトで「.cpp」という拡張子が付加されていますが、 これは C++ のソースファイルに付けられる拡張子なので、C言語としてコンパイルされません。
「.cpp」の部分を「.c」に直して作成するようにして下さい。

C4996警告

strcpy関数(⇒リファレンス)などの一部の関数を使うと、警告を発します。 前述の SDLチェックが有効になっている場合には、エラーになります。

#include <stdio.h>
#include <string.h>

int main(void)
{
	char s[5];

	strcpy(s, "abc");  /* C4996 warning */
	puts(s);

	return 0;
}

この警告は、使用を推奨されなくなった関数が呼び出された場合に発生しますが、 C言語で使用機会の多い標準関数も含まれているため、当サイトのC言語編のサンプルプログラムでも、 この警告が起こることがあります。 これは、それらの関数には何かしらの危険性があるからです。
例えば、strcpy関数は、第1引数で指定した受け取りバッファのサイズを超える大きさのコピーを行うと、 バッファオーバーフロー(C言語編第6章)を起こして、メモリを破壊してしまいます。 それを承知で、注意して使うというのが従来のやり方でしたが、より安全な方法へ置き換えることも検討するべきです。

この警告に対処する方法は幾つかあります。

より良い関数へ置き換える

推奨されなくなった関数には、普通はより良い代替関数が存在していますから、 そちらへ移行すれば対処できます。
例えば、strcpy関数であれば、strcpy_s関数という代替関数があります。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>  /* _countof */

int main(void)
{
	char s[5];

	strcpy_s(s, _countof(s), "abc");
	puts(s);

	return 0;
}

strcpy_s関数は、第2引数に、コピー先のバッファのサイズ(要素数)を指定するようになっています。 第3引数がコピー元になります。 第2引数に指定したサイズ以上のコピーは行われないようになり、バッファオーバーフローを起こさなくなります
配列の要素数は、stdlib.h に定義された _countofマクロで算出できます。 (ワイド文字列(C言語編第47章)を使うことを考えると、sizeof演算子よりも、このようなマクロを利用する方が簡単です)。

1つの問題として、strcpy_s関数、_countofマクロはいずれも、マイクロソフトが独自で用意したものであり、 C言語の標準規格には含まれていません。 従って、他のコンパイラではコンパイルできません。

先ほどのサンプルプログラムにおいて、コピーする文字列を "abcde" のように、 バッファサイズに収まらない大きさにして実行すると、strcpy_s関数内でエラーを検出します。
デバッグビルドでは、アサート(C言語編第28章)によって停止しますが、 リリースビルドではハンドラ関数が呼び出されます。 ハンドラ関数は、_set_invalid_parameter_handler関数を使って、独自で用意したものを登録しておけます。 登録しなければデフォルトの挙動を取りますが、これはプログラムを終了させるというものです。
なお、デバッグビルド時のアサートは、_CrtSetReportMode関数によって無効にできます。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>  /* _countof */
#include <crtdbg.h>  /* _CrtSetReportMode */

void invalid_parameter_handler(
	const wchar_t* expression,
	const wchar_t* function, 
	const wchar_t* file, 
	unsigned int line, 
	uintptr_t pReserved)
{
	puts("error!!");
	exit(1);
}

int main(void)
{
	char s[5];

	_set_invalid_parameter_handler(invalid_parameter_handler); /* ハンドラを登録 */
	_CrtSetReportMode(_CRT_ASSERT, 0);  /* デバッグ時のアサートを無効化 */

	strcpy_s(s, _countof(s), "abcde");  /* invalid_parameter_handler が呼び出される */
	puts(s);  /* 実行されない */

	return 0;
}

代替関数を呼ぶたびに、これらの準備が必要な訳ではなく、 ハンドラ関数の登録、アサートの無効化は、プログラムの最初の方で1回しておくだけです。

#pragma で抑制する

C言語の #pragma(C言語編第29章)を使用して、警告を抑制することができます。

#pragma warning(disable:4996)

#include <stdio.h>
#include <string.h>

int main(void)
{
	char s[5];

	strcpy(s, "abc");
	puts(s);

	return 0;
}

#pragma warning は、VisualC++ の独自機能です。 "(disable:XXXX)" の XXXX の部分に警告の番号を記述することで、 その位置より後方では、その番号の警告が抑制されます。

この方法は、警告を出さなくしているだけなので、危険性を排除できた訳ではないことに注意しなければなりません。

_CRT_SECURE_NO_WARNINGS で抑制する

C4996警告が、C言語の標準関数の利用によって起きているのであれば、 _CRT_SECURE_NO_WARNINGS を define することで抑制することができます。

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <string.h>

int main(void)
{
	char s[5];

	strcpy(s, "abc");
	puts(s);

	return 0;
}

#pragma で抑制するよりも、こちらの方が限定的な意味を持ちますが、 これもやはり、警告を出さなくしているだけであって、危険性を排除できた訳ではないことに注意しなければなりません。

_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES で置き換える

strcpy関数を strcpy_s関数へ置き換えるように、各関数を代替関数へ置き換えれば、 警告を対処できますが、全てを書き換えていくことが大変であったり、 別のコンパイラではそういった代替関数が無かったりもします。

VisualC++ の場合、_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES を使うことで、 代替関数への置き換えを自動的に行ってくれます。

#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1

#include <stdio.h>
#include <string.h>

int main(void)
{
	char s[5];

	strcpy(s, "abc");
	puts(s);

	return 0;
}

単に定義するのではなく、1 に置換するように使うことに注意して下さい。

この定義によって、strcpy関数を使っている箇所は、自動的に strcpy_s関数に置換されます。 例えば、先ほどのプログラムでの strcpy関数の呼び出しは、次のように置き換わります。

strcpy_s(s, 5, "abc");

なお、strncpy関数(⇒リファレンス)のように、元々文字数を指定するようなタイプの関数に対しては、 追加で、次の1文が必要です。

#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1

この手法が一番望ましい対処ではありますが、C++ の機能を利用しているため、C言語では使用できません

参考リンク

更新履歴

'2017/6/27 「C言語を使う場合」の項を追加。

'2014/12/21 「Visual Studio Community 2013」について追記。

'2014/2/8 新規作成。



開発ツールの情報 のトップページへ

Programming Place Plus のトップページへ