何となく Blog by Jitta
Microsoft .NET 考

目次

Blog 利用状況
  • 投稿数 - 761
  • 記事 - 18
  • コメント - 35944
  • トラックバック - 222
ニュース
  • IE7以前では、表示がおかしい。div の解釈に問題があるようだ。
    IE8の場合は、「互換」表示を OFF にしてください。
  • 検索エンジンで来られた方へ:
    お望みの情報は見つかりましたか? よろしければ、コメント欄にどのような情報を探していたのか、ご記入ください。
It's ME!
  • はなおか じった
  • 世界遺産の近くに住んでます。
  • Microsoft MVP for Visual Developer ASP/ASP.NET 10, 2004 - 9, 2011
広告

記事カテゴリ

書庫

日記カテゴリ

ギャラリ

その他

わんくま同盟

同郷

 

とか書きながら、養護するつもりはない。しかし、歴史を知っておく必要はあると思います。

Win32 API のリファレンスを見ていてよく見かける(無理矢理組み合わせた、かも)、「lpctstr」という表記。これを、分解してみようかと思います。

まず、「p」から。これは、Pointer の p です。C 言語において、「文字配列」と「文字列へのポインタ」は、同じように扱えてしまえますが、実は違うものです。そのため、「ポインタであること」を明示するのは、読むとき、保守するときに有用です。

次、「l」。これ、よくわかりません。いろいろ読んでいるうちに「これかな?」と思ったのは、「local」か、「long」の「l」です。大昔、扱えるメモリ量が少なかったり、少ない故に小さいバイト数でいろいろ扱うために、DLL や EXE の境界を越えてポインタを渡せなかったようです。「ポインタ」に、「起点からの距離」を表すものと、「絶対距離」を表すものがあった様です。このうち、「起点からの距離」は、起点が違えば指す場所が変わってしまいます。あるいは、「GlobalHeap」という関数がありましたが、特定のプロセスのみで使えるアドレスと、Windows 全体で使えるアドレスか。そのため、これらを分けるために付けられたようです。はい、そこの人!!鵜呑みにしない。自分で確認すること。なんにしても、Windows 2000 の頃には、分ける必要がなくなっています。

次、「c」。これは、Const の c です。関数の引数に対して、「この引数の値は、関数内で変化させない」事を示すために付けられます。関数の入力、出力を明示するために使うわけです。これも、C++ になって const で修飾した場合、コンパイラがエラーを出します。このため、変数の修飾に使用して明示する必要はなくなっています。

次、「t」。これは、Multi-byte charactor set と、wide charactor set の、どちらにでも変化するよ、を表しています。そのため、文字(列)にしかつきません。Win32 API 関数の最後につく、A とか W と同じカテゴリです。

そして、「str」。これは String です。C では、char は「文字」だけでなく、「1バイトの数値」の意味も持っています。このため、「char a[10];」だと、「10バイトのデータ」なのか、「最大9文字の文字列」なのか、わかりません。そこで、str を付け、「文字列」であることを明示したわけです。

他に、整数値につく「i」があります。これは、整数といえど、割り算をすると浮動小数点型に変換されることがあります。こういった、暗黙の変換を防ぐ(注意を向ける)意図を持ちます。

また、short の場合、演算結果がオーバーフローする可能性が高くなりますから、これをレビューで検出できるようにすることもあります。

あとは、符号のあるなしについても、ありますかね?signed char の 0x80 と、unsigned char の 0x81 を比べると、どちらが大きいか。これは、最近だとコンパイラが警告を出してくれます。また、符号の有無と同じように、縮小変換についても警告、あるいはエラーとなるようにコンパイラが修正されています。したがって、変数名に明示する必要はなくなっています。


このように、単に型を示していたのではなく、目視レビューで間違いを検出しやすくするための工夫だったわけです。で、コンパイラが検出するようになったからか、Visual Studio 2008 に付属する SDK のドキュメント(英語)では、これらのシステム ハンガリアンな記述がなくなっています(作業中かもしれない)。

このように、C/C++ では、意味がある事でした。しかし、すべての言語で意味があることではない、あるいは、同じ記号であっていいわけではありません。

VB や C# のコードで、型名を明示する必要はありません。特に、「クラスだから」と、「cls」を頭に付けているようなものは、全く意味がありません。

そんな無駄なことをするより、なぜそのような符号を付ける必要があるのかを知り、その上で、使用している言語にそれが必要なのか、同じようにしていいのか、他に追加することがあるか、といったことを考える事の方が重要ではないでしょうか。「システム ハンガリアン使うな」とは言いません。しかし、使う前に、それにどんな意味があるか、知って欲しいと思います。

投稿日時 : 2008年7月7日 21:54
コメント
  • # re: システム ハンガリアンを養護してみるテスト
    ゆーち
    Posted @ 2008/07/07 23:15
    lは、LONG の意味だと思います。
    tに関する考察は、あちきにはびっくりでしたが、たぶん、認識の違いだと思います。おそらくcとtは別れていなくて、ConsT の意味だと思います。

    「ハンガリアン表記」というスタンスに関して、あちきは絶対反対派ではありませんが、テラ反対派ですw

    Windowsプログラミングが、ほとんどCで書かれているとき、ハンガリアン表記は
    「型」を識別するのか
    「スコープ」を識別するのか
    「メモリ内のサイズ」を識別するのか
    に分かれていて、ごっちゃになってました。
    この時点で、あちきは却下してましたw

    C++でオブジェクト指向がMFCによって歪曲されて蔓延したとき
    いまわしき「m_」が統合環境で自動的に付けられるようになりました。

    文字列・コンテナを除いて、「型」の意味するものを考えてみてください。
    あるカウンタ用の数字iがあるとき
    iの上限が 127,255,32767,65535,...であるかどうか、などは、現実世界のシステムをプログラムにする場合において何の意味があるというのでしょう。
    ある検索条件に一致するデータベース上の件数は、8ビット、16ビットあるいは32ビットに収まると限られるものだと永久に保証できるのでしょうか?
    システムが32Kの許容範囲で動くとして、やがて肥大化したときの対応で、64Kとか64ビット長をサポートするとき、ローカルに書いた変数名を変更しますか?
    「メモリ内のサイズ」を表現する[l]というハンガリアン表記は、将来的にプログラマをいじめるものです。きっぱり。

    ほぼ同じ理由で「型」を意味するハンガリアン表記は将来的に破綻してしまうと信じています。

    「スコープ」について m_はナンセンスですが、プログラミング言語ソースの可読性の意味で、これだけは重要だと思っています。
    クラスメソッド中に、メンバの「名前」に関するコードを書く場合、
    int age = m_age;
    と書かせる時点で、プログラマの労力を2倍にしてる、とあちきは思っています。
    オブジェクト指向の思想は、『すべてのデータはオブジェクトである』です。
    クラスにメンバがあってこそ、その操作をプログラミングできます。

    int local_age = Age;
    とか
    int age = Age;
    #引数への代入なら age_ = Age とか
    であれば、許せるなぁと思っています。

    『変数』を「引数」と「ローカル変数」と「グローバル変数」と「メンバ変数」に分ける目的でのハンガリアン表記なら、許してもOKだとおもいます。

    時代背景的に、クラスメンバが後付けになってしまっているのが混乱の理由だと思いますね。

    .NET でシステムが提供するクラスのメンバに m_ が付いていなくて本当に良かったと、胸をなで下ろしているところですw
  • # re: システム ハンガリアンを養護してみるテスト
    れい
    Posted @ 2008/07/07 23:40
    > はい、そこの人!!鵜呑みにしない。自分で確認すること。

    はい!
    Jittaさんが前も鵜呑みにしちゃいけないってました!

    でも、
    鵜呑みにしちゃいけないっていうのは
    鵜呑みにしていいのでしょうか?

    私はJittaさんの言いつけどおり、
    鵜呑みにしちゃいけないっていう部分を鵜呑みにせずに、
    それ以外は鵜呑みにすることにしました!
  • # re: システム ハンガリアンを養護してみるテスト
    えムナウ
    Posted @ 2008/07/08 2:30
    >tに関する考察は、あちきにはびっくりでしたが、たぶん、認識の違いだと思います。おそらくcとtは別れていなくて、ConsT の意味だと思います。

    t は TCHAR の Tだよ。
    Jittaさんが正しいです。
  • # re: システム ハンガリアンを養護してみるテスト
    biac
    Posted @ 2008/07/08 10:22
    t は Text の T っす。 ( 正確には "generic-Text" 「汎用テキスト」 らしい )
    http://msdn.microsoft.com/en-us/library/7dzey6h6.aspx

    前世紀には、 LPCTSTR って書いてあると、 アタマの中では 「ろんぐ・ぽいんた、こんすと、てきすと・すとりんぐ型」 って読んでましたね~ f(^^;
    # 64KB の外へ出るのは、昔はタイヘンだったんだぞ~w

    でも、 LPCTSTR は型なんで、 変数宣言では、
    LPCTSTR pszPath;
    とか、 文字列を指すポインタだと分かる程度のプリフィックスしか付けませんでしたけど。
    ※ psz: ぽいんた、すとりんぐ・ぜろたーみねいてっど ( Null で終わる文字列へのポインタ )
  • # re: システム ハンガリアンを養護してみるテスト
    シャノン
    Posted @ 2008/07/08 11:08
    > なんにしても、Windows 2000 の頃には、分ける必要がなくなっています。

    95で既に意味なくなってます。
    昔はポインタに near と far があったようですね。前者が同セグメント内で、後者が異セグメント間でしたっけ?
    far は long がついて LPCTSTR になるけど、near は L がなくて PCTSTR。
    ま、俺がはじめて「ぷるぐらみんぐ」をやったときには、既に過去の遺物でしたけどー。
  • # re: システム ハンガリアンを養護してみるテスト
    とっちゃん
    Posted @ 2008/07/08 11:38
    へーい。古い人が来ましたよー

    LPCTSTR は LP-C-TSTR と分解です。

    LPは、LONG POINTER(Long-Range Pointer)ですね。
    これで一語として読まねばなりません。
    要するに、FAR ポインタ型をさすのですが
    これについては、16bit時代のお話なので割愛。
    ちなみに、類似のものには
    P(ポインタ型)、NP(NEAR ポインタ型)があります。
    NP はもう残ってませんがw

    LPにせよ、NPにせよどちらも、16bit時代の名残なので、今は L そのものには何の意味もありません。

    定義を見ないとわかりませんが、LPTSTR は TCHAR* であって、TCHAR FAR* にはなっていなかったはずです。

    C については、すでに書いてあるとおり、const の略ですね。

    もう一方のTSTR についても。。。
    C/C++ では、文字列という型がないのはすでにご承知&だれか書いてるんで省略として、
    STR 自身は「この型は文字列を意味しますよ。」ということを表現する「型表現」になります。
    したがって、文字コード種別を意味する修飾語として
    「無記述(C/C++オリジナルのANSI/MBCS)」、「UNICODE文字を意味するwchar_t の略語のW」
    そして、コンパイルオプションでこれら二つを切り替える「generic-Textの略語のT」と
    文字コードをつけて、文字列型を表現します。

    したがって、T と STRは分けてはならず、TSTR で1つと覚えておかねばなりません。
  • # re: システム ハンガリアンを養護してみるテスト
    ゆーち
    Posted @ 2008/07/08 17:15
    へぇ・・・「TCHAR」のTだったんだぁ。
    勉強になりますた。m(_._)m
  • # re: システム ハンガリアンを養護してみるテスト
    Jitta
    Posted @ 2008/07/08 23:02
    ゆーちさん、れいさん、えムナウさん、biacさん、シャノンさん、とっちゃんさん、コメントありがとうございます。

    まず、本文に突っ込み。

    > これは、整数といえど、割り算をすると浮動小数点型に変換されることがあります。
     これ、嘘ですね。正解は、こちら→ http://blogs.wankuma.com/hijun/archive/2008/07/07/147810.aspx
    C でも、".0" を付けてやらなきゃいけなかったはず。

    -----

    > lは、LONG の意味だと思います。
     最近まで残っていたので、「長い範囲で参照できる」という意味で、long だと思うのですけど、エビデンスが...

    > テラ反対派ですw
     ん。。。元々は、「変数が意図するものを明示する」で、たとえば「会員氏名」の変数名を「memberName」にするのと、ほぼ同じ理由なんですね。で、C だとこれが、「静的に領域が確保されている」のか、「動的に領域を確保しなければならない」のかによって、扱い方が変わってきますから、言語やコンパイラを含めた開発環境によっては「必要」だと思うのです。
     そういう意味で、「型」も「スコープ」も「メモリ内のサイズ」も、意識しなければならないものだったわけで、「他人が使うもの」に対してそれらを明示することは、必要だったかな、と思います。
     ただ、どこかで、最初に付けられた意図が勘違いされて伝わってしまっているのですね。それが残念に思います。

    -----

    > 鵜呑みにしちゃいけないっていうのは
    > 鵜呑みにしていいのでしょうか?
     そこに突っ込まれるとは、夢にも思っていませんでした(T^T)
     あのね、前に、「~だと思う」と書いているのに、「投稿数がすごいからそのまま信じました」という人がいたので、「これ、よくわかりません。いろいろ読んでいるうちに「これかな?」と思った」を、念押ししたですよ。

    -----

    > t は TCHAR の Tだよ。
    > t は Text の T っす。 ( 正確には "generic-Text" 「汎用テキスト」 らしい )
    > T と STRは分けてはならず、TSTR で1つと覚えておかねばなりません。
     補足どうもです~

    -----

    > 95で既に意味なくなってます。
    > ま、俺がはじめて「ぷるぐらみんぐ」をやったときには、既に過去の遺物でしたけどー。
     あんれまぁ、そうでスカイ。。。若いって、いいなぁ...

    > 昔はポインタに near と far があったようですね。前者が同セグメント内で、後者が異セグメント間でしたっけ?
     それかぁ。その頃は UNIXer だったので、「DOS だと64KB までしか表現できないんだって!」とか、軽く流してました。で、DOS 側のプログラムも作らなければならなくなって、orz あの頃使っていたのは、「ラティス C」だったかなぁ?

    -----

    > 古い人が来ましたよー
    「古い人」いうなぁ(T^T)

    > LPTSTR は TCHAR* であって、TCHAR FAR* にはなっていなかったはずです。
    ですです。

    -----

    > でも、 LPCTSTR は型なんで、
     あちゃ~。。。覚え間違いですorz
  • # re: システム ハンガリアンを養護してみるテスト
    Jitta
    Posted @ 2008/07/08 23:10
    このエントリに、「char 0x80 msdn」をキーに、Google からリファラがあるんだけど。何を調べているのだろう?
タイトル  
名前  
Url
コメント