0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

scanfは領域を破壊するか?

Last updated at Posted at 2015-02-24

文字列を数値(short,byteも)に変換する際に、scanfを利用していたのだけど、「領域破壊するんじゃない?」と言われて調べた。

scanf 関数の型フィールド文字|(MSDN)

d 10 進整数。int へのポインター。

※ソースはswscanf_sを利用しているが、結果は同じだと思う。

test.cpp
	//  swscanf_sは領域を破壊するか?
	int rc = 0;

	byte			bary[10];
	unsigned short	usary[10];
	short			sary[10];
	unsigned int	uiary[10];
	int				iary[10];

	byte			bvalue = 0;

	std::wstring	wstrTempD = L"255";

	// 破壊していないことを確認するため、既定値として0x11をすべてに設定する。
	memset(bary,	0x11,	sizeof(bary));	// ->0x11,0x11....
	memset(usary,	0x11,	sizeof(usary));	// ->0x1111,0x1111....
	memset(sary,	0x11,	sizeof(sary));	// ->0x1111,0x1111....
	memset(uiary,	0x11,	sizeof(uiary));	// ->0x11111111,0x11111111....
	memset(iary,	0x11,	sizeof(iary));	// ->0x11111111,0x11111111....

	rc = swscanf_s(wstrTempD.c_str(),L"%d",bary);	// ->0xff,0x00,0x00,0x00,0x11,....
	rc = swscanf_s(wstrTempD.c_str(),L"%d",usary);	// ->0x00ff,0x0000,0x1111,....
	rc = swscanf_s(wstrTempD.c_str(),L"%d",sary);	// ->0x00ff,0x0000,0x1111,....
	rc = swscanf_s(wstrTempD.c_str(),L"%d",uiary);	// ->0x000000ff,0x11111111....
	rc = swscanf_s(wstrTempD.c_str(),L"%d",iary);	// ->0x000000ff,0x11111111....

	bvalue = bary[0];	// アクセスすると、255ではあるが、領域を思い切り破壊…。

やっぱ壊してました。

test.cpp
	// 変換としてはintに格納し、byteやshortにキャストして使うのがメモリ的には安全そう。
	bvalue = (byte)uiary[0];
	// 精度が落ちる可能性があるので、変換後にサイズチェックした方がいいかもね!

おまけ。%cの時の挙動

test.cpp
	memset(bary,	0x11,	sizeof(bary));
	memset(usary,	0x11,	sizeof(usary));
	memset(sary,	0x11,	sizeof(sary));
	memset(uiary,	0x11,	sizeof(uiary));
	memset(iary,	0x11,	sizeof(iary));

	lRc = swscanf_s(wstrTempD.c_str(),L"%c",bary);	// ->0x32,0x00,0x11,0x11,0x11,....
	lRc = swscanf_s(wstrTempD.c_str(),L"%c",usary);	// ->0x0032,0x1111,0x1111,....
	lRc = swscanf_s(wstrTempD.c_str(),L"%c",sary);	// ->0x0032,0x1111,0x1111,....
	lRc = swscanf_s(wstrTempD.c_str(),L"%c",uiary);	// ->0x11110032,0x11111111....
	lRc = swscanf_s(wstrTempD.c_str(),L"%c",iary);	// ->0x11110032,0x11111111....

文字だから?か、後ろにNULLが挿入されるのかな。それか、wcharだからかもしれませんね。

###追記
short型は"%hd"で、char(byte)は"%hhd"で読み取れるとのご指摘を確認!
調べてみたところ、プレフィックスで読み取れる範囲を指定できるようです。

scanf 関数の文字幅指定|MSDN

test.cpp
			byte			bary[10];
			unsigned short	usary[10];
			short			sary[10];
			unsigned int	uiary[10];
			int				iary[10];

			byte			bvalue = 0;

			std::wstring	wstrTempD = L"255";

			// 破壊していないことを確認するため、既定値として0x11をすべてに設定する。
			memset(bary,	0x11,	sizeof(bary));	// ->0x11,0x11....
			memset(usary,	0x11,	sizeof(usary));	// ->0x1111,0x1111....
			memset(sary,	0x11,	sizeof(sary));	// ->0x1111,0x1111....
			memset(uiary,	0x11,	sizeof(uiary));	// ->0x11111111,0x11111111....
			memset(iary,	0x11,	sizeof(iary));	// ->0x11111111,0x11111111....

			rc = swscanf_s(wstrTempD.c_str(),L"%hd",bary);	// ->0xff,0x00,0x11,....
			rc = swscanf_s(wstrTempD.c_str(),L"%hd",usary);	// ->0x00ff,0x1111,....
			rc = swscanf_s(wstrTempD.c_str(),L"%hd",sary);	// ->0x00ff,0x1111,....
			rc = swscanf_s(wstrTempD.c_str(),L"%hd",uiary);	// ->0x111100ff,0x11111111....
			rc = swscanf_s(wstrTempD.c_str(),L"%hd",iary);	// ->0x111100ff,0x11111111....

			// 破壊していないことを確認するため、既定値として0x11をすべてに設定する。
			memset(bary,	0x11,	sizeof(bary));	// ->0x11,0x11....
			memset(usary,	0x11,	sizeof(usary));	// ->0x1111,0x1111....
			memset(sary,	0x11,	sizeof(sary));	// ->0x1111,0x1111....
			memset(uiary,	0x11,	sizeof(uiary));	// ->0x11111111,0x11111111....
			memset(iary,	0x11,	sizeof(iary));	// ->0x11111111,0x11111111....

			rc = swscanf_s(wstrTempD.c_str(),L"%hhd",bary);	// ->0xff,0x00,0x00,0x00,0x11,....
			rc = swscanf_s(wstrTempD.c_str(),L"%hhd",usary);// ->0x00ff,0x0000,0x1111,....
			rc = swscanf_s(wstrTempD.c_str(),L"%hhd",sary);	// ->0x00ff,0x0000,0x1111,....
			rc = swscanf_s(wstrTempD.c_str(),L"%hhd",uiary);// ->0x000000ff,0x11111111....
			rc = swscanf_s(wstrTempD.c_str(),L"%hhd",iary);	// ->0x000000ff,0x11111111....

"%hd"は領域を破壊せずに読み取れました!"%hhd"は%dと同じ挙動に…。

追記

Visual C++では%hdまでで%hhdがないとのことでした。無念。
scanf 関数の文字幅指定|MSDN

0
0
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?