質問: sizeof(szBuf) / sizeof(TCHAR); ``` ### 補足情報(FW/ツールのバージョンなど) Microsoft Visual C++ 2010 Express C言語 WIN32 ユニコードビルド Windows7
回答: 余談ですが、このキャストは安全ではないです。 ref: (翻訳)C/C++のStrict Aliasingを理解する または - どうして#$@##@^%コンパイラは僕がしたい事をさせてくれないの! - yohhoyの日記 やるとしたら ``` TCHAR szBuf256] = { 0 }; const WORD size = (WORD)(sizeof(szBuf) / sizeof(TCHAR)); memcpy(szBuf, size, sizeof(size)); ``` じゃないでしょうか。 なんか無駄に回答者が多くついている割に、質問者の理解に繋がっていないようなので、真面目に回答します。 仮に`TCHAR`が`char`だとしましょう。 ``` TCHAR szBuf[256]; *(LPWORD)szBuf = sizeof(szBuf) / sizeof(TCHAR); ``` `szBuf`は`TCHAR [256]`型の変数です。C言語では配列は3つくらいの例外を除いて式中では常に配列の先頭要素へのポインタとして扱われるのでした。 ポインタ型はつねにもととなる方があってそこから派生して作られます。 ``` int n = 0; int* np = &n; ``` この例なら`np`の型は`int*`型ですが、これは`int`型から派生してできますよね? これは何を意味するかと言うと、pointerをdereferenceするときに(=たぐり寄せたとき)、メモリーをどう扱えばいいかを示すのが派生元の型である、ということができます。この例では`np`をdereferenceしたときの領域の大きさ、bitの使われ方は`int`型と同じだよ、といううのが`int*`型の意味ですね。 ``` TCHAR szBuf[256]; *(LPWORD)szBuf = sizeof(szBuf) / sizeof(TCHAR); ``` さて、本題に戻りましょう。この配列(=`szBuf`)の先頭要素へのポインタを`LPWORD`型(=`WORD*`型=16bitの符号なし整数型へのポインタ型)にキャストするというのはどういうことかというと、メモリーをどう扱えばいいかを偽る、という作業になります。配列`szBuf`のメモリー領域は本当は`TCAHR`の配列ですが、`WORD`型の変数であると偽るわけです。 ![メモリー では質問者さんがいう > > まだよくわからないのですが、szBuf[0]からszBuf[256]までの要素のそれぞれを2バイトの領域として扱い、szBuf[0]にsizeof(szBuf) / sizeof(TCHAR)の結果を保存するという意味であってますか? > > > は誤りなのでしょうか?じつはあながち間違いでもありません。(`szBuf[256]`じゃなくて`szBuf[255]`でしょうが、ケアレスミスですよね?) Re:Cのポインタと配列の関係について考察してみる を読んでいただきたいのですが、ポインタは単にdereferenceして指し示す先を取り出すだけではなくて、ポインタ演算によってポインタの指す場所を移動させる、イテレータのような機能も持つのでした。 ``` int n1 = 3; int arr[2] = { 0 }; int* p; p = &n1;//OK p++;//OK p = arr;//OK p++;//OK ``` 言い換えると`int`型は要素数1の配列とみなすこともできるわけです。というかポインタには要素数の情報がありませんので、上のコードのような芸当ができるのでした。 つまり、 > > szBuf[0]からszBuf[256]までの要素のそれぞれを2バイトの領域として扱い > > > は正しく直すと 要素数不明の`WORD`型の配列と偽る となります。 で追記前に書きました話に戻ります。 先程 > > メモリーをどう扱えばいいかを偽る、という作業 > > > と書きましたが、こういう作業はコンパイラがプログラムの最適化をしやすくするために、多くの場合で禁止されています。言い換えると`szBuf`は何も変更されないというコードをコンパイラが生成する可能性があるということです。 ではどうすればいいのか、細かい理屈は冒頭でリンクしていてこのコメント欄にも書き込みされている yohhoyさんの記事を見ていただくとして、結論から言うと`memcpy`でbyte copyすればよいです。念の為`memcpy`とは何をするものなのか`man memcpy`でぐぐって確認すると > > https://linuxjm.osdn.jp/html/LDP_man-pages/man3/memcpy.3.html > > memcpy() はメモリー領域 src の先頭 n バイトを メモリー領域 dest にコピーする。コピー元の領域と コピー先の領域が重なってはならない。重なっている場合は memmove(3) を使うこと。 > > > とあります。