文字列を数値(short,byteも)に変換する際に、scanfを利用していたのだけど、「領域破壊するんじゃない?」と言われて調べた。
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"で読み取れるとのご指摘を確認!
調べてみたところ、プレフィックスで読み取れる範囲を指定できるようです。
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