win7(64bit)の悲劇 - どこから湧くのよこの警告 -

 多少間が空いたけれども

今回はWin7というよりは、VC2008以降のお話。

普通にC標準関数を使っていると、こんな警告がわんさか出てくるかと思うんですが…


1>...\windows_main.cpp(147) : warning C4996:
'fopen': This function or variable may be unsafe.
Consider using fopen_s instead.
To disable deprecation,
use _CRT_SECURE_NO_WARNINGS.
See online help for details.
1>c:\program files (x86)\microsoft visual studio 9.0\vc\include\stdio.h(237)
: 'fopen' の宣言を確認してください。
(改行は体裁の関係で追加したものです。)

fopen()のみならず、strcpy()や_itoa()でも出ます。

特に前回の私同様、移行組の場合はそれはもうわんさか出ます…(苦笑)



 まぁ、警告文をよく読んでみると、

「fopen():この関数(変数は)安全ではないかもしれないので、fopen_s()を使ってね♪」

といった感じのことが書いてある。

じゃぁ、「fopen→fopen_sで置換かければいいんじゃね?」…とか思ってると、

これが通用しない。

何でかというと…、

fopen() - MSDN
fopen_s() - MSDN
…オワカリイタダケタダロウカ?(謎)

早い話、

引数が違う。

どうも、「エラーはWINの標準エラーの方に出すから、そっちで判断しろやゴルァ!」ということらしい。

んまぁ、正直な所、あくまでも「警告」なので、

ビルドは通るし、挙動的にも問題ない。*1



 ただ、結構な量の警告が出るので、気持ち悪いというのもあるが、

何より、本物の警告/エラーを見逃す恐れがある。



 まぁ、なので、警告に対処しようという話。

(ここから本題)

まぁ早い話、defineでいい。

ただし、冒頭のfopen()がdefineでは対応できないので、要別途対応。

で、↓が具体例。



・cast_vc.h

/*=====================================
VC2008対応用標準関数変換マクロ
=====================================*/
#ifndef	__CAST_VC__
#define	__CAST_VC__


// VC2008対応用
#define	fopen(file,type)	Fopen(const_cast<char*>(file),const_cast<char*>(type))
#define _itoa(num,buf,rate)	_itoa_s(num,buf,strlen(buf),rate)
#define	strcpy(dst,src)		strcpy_s(dst,strlen(src)+1,src)
#define strcat(dst,src)		strcat_s(dst,strlen(src)+strlen(dst)+1,src)
#define strtok(src,div)		STRtoken(src,div)


FILE *Fopen( char *file, char *type );
char *STRtoken( char *src, const char *div );

#endif	// < __CAST_VC__

・cast_vc.cpp

#include <stdio.h>
#include <string.h>		// strtok_s()用
#include "cast_vc.h"


// fopen()→fopen_s()変換用
static FILE *g_fp;

/*=====================================
fopen()→fopen_s()変換用関数
=====================================*/
FILE *Fopen( char *file, char *type )
{
	fopen_s( &g_fp, file, type );
	return g_fp;
}


// strtok()→strtok_s()変換用
static char *g_token;

/*=====================================
strtok()→strtok_s()変換用関数
=====================================*/
char *STRtoken( char *src, const char *div )
{
	return strtok_s( src, div, &g_token );
}

こんな感じの.h、.cppを用意して、

ソースの頭のあたりで

#include "cast_vc.h"

でOK。



 もっといい方法もあるだろうけど、まぁ一時対処には十分でしょう。




*1:挙動的には、置き換えない(=変更を加えない)方が再現性の保障を取れるんじゃないかね…。