第A9回 論理演算必勝テクニック(誰かXORを教えて!:p) 00/03/14

わけあって、ここのところマクドナルド入りびたりなんですが(近くにマクドナルドしかないからなんですけど…)、マクドナルドは土日はハンバーガー半額ではないんですよ!かと言って、土日のハンバーガーは、平日のよりうまいわけでもないんですよ!(当たり前) こんなんで、土日にハンバーガー買う奴いるんかなー?と思ってたら、いましたいました!5つも買ってる馬鹿な奴!!それが、俺!(だめじゃん…)

ちゅーかねぇ、この仕事してると、土日とかわかんなくなってくるんですよ。なんか金を支払うとき、いつもの2倍ぐらいするんだなぁと思ったら、今日は土日なのかーとか思ったりして。2倍ぐらいするなーでなく、正確に2倍してるんですよ(笑) 店員のおばさん(田舎なのでおばさんがマクドナルドで働いているのだ)が、なんとなく気の毒そうな目でこちらを見てたりして…。あーやだやだ(笑)

こういうとき、お金に見合うだけの価値なんてどこにも無いんだと思います。私の場合、学生時代のバイトは法外の安さで働いていたことがあります。法外の高さだったこともありますが(笑) 仕事内容に見合う金額ではなく、そのときの市場性、たとえば自分がかかわったソフトがいくら売れたかなどによって左右されます。しかし、いくら売れるかどうかってのは、ソフト内容以外にも、マーケットの規模、流通能力、営業戦略等々がからんでくるので、自分のプログラミング能力および、技術レベルの高低はほとんど反映されないような気がします。その結果、ALLアセンブラで1ヶ月ぐらいかけて作った3Dのゲーム(名前は秘密:p)より、その場凌ぎで、1週間ほどで作った盗撮マニアのほうが何倍もロイヤリティが高かったりします。

そういうのを目の当たりにするとき、労働に見合う金額なんてどこにも無い(存在しない)んではないかと思います。たくさんお金が欲しいというのではないのです。自分の仕事に見合う金額はいつも貰えないし、そもそも自分の仕事に見合う金額とは何なのでしょうか?あるいは、そんなものは、最初っから存在しなかったのかも知れません。あのマクドナルドのおばさんも、平日の2倍の値段のハンバーガーを5つもやねうらおに売ったとき、どんな思いだったのでしょうか。やねうらおは、分不相応の報酬(多いにせよ、少ないにせよ)をもらうとき、あのおばさんのことを思い出さずにはいられません。

今回のトピックは論理演算です。論理演算が若者の間で大流行!するはずもなく、プログラミングトピックとしてはかなり地味な存在です。今回はそのなかでも、あまり使うことの少ないxor(排他的論理和)について考えてみたいと思います。

ビット演算の面白いところは、ビットごとの演算だと言うことです。そんなの当たり前田のクラッカー!(古い…)と言わずによく考えてください。

ビットごとの演算、それはつまり繰り上がり等が発生して隣のビットを巻き込まない、隣のビットに影響を及ぼさない、それぞれのビットが独立して計算されるという意味です。いま風に言えばMMXアセンブラのPACKED演算に相当するもので、それもPACKED BYTEならぬ、PACKED BIT!なのです。そう考えるとわかりやすいと思います。

xorは、0と1ならば1になる演算ですが、そうとらえるより、1はビット反転子と考えたほうが良いです。以下、1のことをビット反転子と呼びます。

たとえば、

(1 xor 1) xor 1 = 1です

1を1で2回xorするから、2回反転して1に戻ったと、そう考えたほうが多項になったときにわかりやすいです。あるいは、ビット反転子が3つあるから、3は奇数なので、最後に1が残ったのだと。ということは、

A xor 0 = A

です。これは、0は1のときとは違い、何も作用しないからです。

A xor 1 = not A

逆に1はビット反転を生じさせます。

(A xor 1) xor 1= (not A) xor 1 = A

ビット反転2回で、元のに戻りますね。

(A xor B) xor C = (A xor C) xor B

多項xorになってもビット反転子の数だけビットが反転するのですから、その演算順序には関係ありません。つまり交換則が成り立ちます。

A xor A = 0

偶数回のxorでは、ビット反転子の数も偶数なので、演算結果は0になります。
通常、xorというと、特定ビットだけを反転させるのに使います。反転させたいビットを1にしてxorをとれば良いわけですからね。

ところで、XとYとの交換を、以下のようには書けませんか?

void Swap(int& x,int &y){
x = x^y;
y = x^y;
x = x^y;
}

何をやっているかわかりますか? y = x^y;の部分では、その上のx = x^yでxにx^yが入っていますから、y = (x^y) ^ y;になるはずです。交換則により、これはx^(y ^ y)であり、y^yは、0ですから、x^0が残って、これはxですね。つまりy = x^y;の部分でyにはxが代入されたわけです。

同様にその一行下のx = x^y;では、x = (x^y) ^ x;(xはx^y,yにはxが入っている)ですから、同様に交換則とx^x=0から、yが残ります。つまりxにはyが代入されたということです。

見事交換が出来たというわけです。交換のために一時変数を必要としないので、レジスタの少ないアセンブラではよくこの技法をやりました。(常套手段でした) ところが、最近、人に教えるためにC言語の教科書を見ているとこれが練習問題として掲げてあり、「パフォーマンスはともかく、この方法は通常は勧められない。それはなぜか?」とか書いてあるんですよ。回答載ってないし(笑) うひょー助けてくれーって感じ(笑)

演算回数3回の代入回数3回って言うのがネックなんですかねぇ。そりゃ一時変数使ったほうが速いでしょうけど…。あるいは、intがdoubleに替わったりしたら、この技法は使えないとか、そういう意味のことなんでしょうか?そりゃ一時変数使ったほうが汎用性はあるでしょうけれど…。とか思って、その下のヒントを見ると「これはどういう時にうまく動かないか?」とか書いてある。えっ!?動かないの??動かない場合があるの??マジですかー。(笑)

うーん、回答が、わかったかたおせーてください。いまならもれなく、めっさげ(うちの会社で売れ残ったゲームを指す隠語:p)が当たります。(ただし東京都府中市まで取りに来てくださる方のみ)


追加記事(追加2000/03/14 0:10)

はじめまして。ケットシー零式と申します。

XORでSwapの問題点を知っているのでメールしました。

void Swap(int &x, int &y){
x = x^y;
y = x^y;
x = x^y;
}

まず答えからいうと、このSwapでは、xとyに同じもの
(やねうらお注釈:同じ値ではなく、同じ変数の意味)
渡された時に、中身が0になってしまいます。
一時変数を使えばこんなことは起こりません。

私は昔、実際にjavaでこのSwapを使ってバグがでたので
知ることができました。やっぱりただ考えているより、
実際にやってみた方が分かりやすいですね。

ぐはっ。そうなのか…。そうだったのか…。ケットシー零式さん、ありがとうございます!
お約束通り、めっさげを差し上げますので取りに来てください。(いらんて…)

追加記事2(追加2000/03/17 23:30)

Micさんからは、こんなメールをいただきました。

Micといいます。

スーパープログラマへの道でXとYとの交換方法で
こんなのを知っています。

排他的論理和を使わない方法です。(やねうらおさんは知っているかも)

void Swap(int &x, int &y)
{
x = y - x;
y -= x;
x += y;
}

こんなのが確かあったような。
これなら、xとyが一緒でも問題は無いです。

これは面白いですね。これならばdoubleに対してもSwap出来そうですね。このコード自体は、10年ぐらい前に、人のソースを逆アセしてて見たことがあります。(笑)


第AA回 スマートになろう(スマートポインタを考える その1) 00/03/18

とりあえず、2/24日からGameSDKのver.2.00の開発を開始しました。それ使って、ドリキャスへの移植を前提とした、双子のゲーム「Twin Love」を作ってます。ゲームOP画面で、女の子が画面中央に表示されて、それが左右二つに50%ずつのブレンド比率で分かれ、それぞれにモーフィングがかかって、双子それぞれの顔に変化しながら、そのあとブレンド比率を0までゆっくり下げてフェードで消える処理をやるんです。なかなか面白い演出だと思うのですが、そのために描画ルーチンをまるまる書き直しています。

あと、3角形でそれぞれの頂点でのブレンド比率を指定して、それらを線形補間するような段階的なブレンド転送もやります。グローシェーディングに対抗して、グローブレンディング。(なんじゃいそりゃ…)

ついでに、いまのゲームのフレーム(yaneurao Game SDK version 1.5)も気にいらないので、全面的にリライトしています。一応、目標は、

済 ◎ マルチスレッド、マルチウィンドゥの採用。
済 ◎ CGameFrameやSCENE管理なんてダサイので、やめる。
済 ◎ CDDA wrapperはマルチドライブ指定に対応。
済 ◎ CD再生等に対してタイミングをとりながら画像を流せるようにする。
済 ◎ WAVE,CDのマスターボリューム調整。
済 ◎ CSound再生クラスは、圧縮WAVEファイル(WAVEタグ付MP3等)対応。
済 ◎ オーディオミキサを直接操作し、CDなどに対して擬似的にフェードイン/フェードアウトを実現するクラス。
◎ DirectMusic対応。
◎ MPEG movie再生対応。
◎ 描画ルーチンをDirectDrawを使わないように書き直し始める
左右反転+回転拡大縮小+αブレンド+サテュレーションブレンド機能。
クロスフェードルーチン。(現バージョンの5倍ぐらい高速なやつ)
三角テクスチャ変形貼り付け。多角形テクスチャ貼り付け。自由変形。
モーフィング。簡易3D機能。高速ぼかし。
◎ 描画ルーチンのアセンブラ化。およびMMX対応。
◎ 256色時のパレット処理強化。
◎ High Color以上のときのソフトウェアパレット。
◎ DirectDrawを使う描画と、使わない描画を同じインターフェースで行なえるように。
◎ CPlaneは、susie plug-in対応。
◎ スクリーンセーバー対応に。
◎ 3D 描画対応に。
◎ スクリプト言語はオブジェクト指向型に大幅拡張。

です。このまま順調にいけば、来月末にはαバージョンを公開できるはずです。(でも、いま5月に発売する「夜這いマニア」の追い込みなんですけど:p)

マルチウィンドゥのほうは、

CDebugWindow win; // デバッグウィンドゥの宣言
win.Run(); // ウィンドゥの作成とメッセージループの開始
win.Out("i = %d ",i);

なんてやって、簡単にデバッグできます。非常に便利です。一つのアプリケーションクラスが、一つのウィンドゥとそれに対するメインスレッド、メッセージループのスレッドを保持しています。(いろいろ実装上の問題もあるのですが、詳しいことは機会を改めて書きます)

今回は、配列に対するスマートポインタの実装についてです。いい加減、C++でスマートポインタをサポートして欲しいものです。もちろん、テンプレートでのサポートではなく、Javaのような言語的なサポートが必要だと思います。C++の新しいコンパイラならばスマートポインタauto_ptrをテンプレートとしてサポートしていることは知っていますが…。

まあ、このauto_ptrの使いかたは簡単で、

auto_ptr<CApp> m_lpApp;

とやって使います。

スマートポインタの概念としては、普通のポインタと同じように使えて、かつ、m_lpAppは初期値NULLで初期化され、CAppの所有権を持ったままこのスマートポインタが解放されるときには自動的にm_lpAppをdeleteするというものです。(本当は、参照カウントが0になったときに解放されたほうが良い気がしますが計算コストからすると、これが妥当でしょう) これにより、deleteし忘れが無くなるのが大きいです。たとえば、C++的な例外処理を発生させる場合を考えてみましょう。

XXX* xxx = new XXX;
if (IsError()) throw;

例外が発生するとその関数から即座にリターンしてしまうのですが、その時点でnewしていたポインタを解放する必要があるかも知れません。このときに、何らかのエラー判定のifごとに

if (IsError()) {
  delete xxx;  // こういうのが必要
  throw;
}

なんてやるのは、少しダサイです。このときxxxがスマートポインタであれば、throwによってスコープアウトしたときにそのデストラクタが自動的に解放してくれます。(ちなみにdelete xxxの部分でxxxがNULLかを判定する必要はありません。delete NULLが何も行なわないことは保証されています。逆に要素数が0の配列をnewするとメモリ例外が発生します。素人が書いたプログラムだとたいていそのへんのチェックが甘くて、下手なことをするとそれが原因で落ちるんですが^^)

ところで、スマートポインタの大前提として、普通のポインタのごとく振舞うことが大切です。C++のauto_ptrもそれに近づける努力はしてあります。たとえば、CAppはCAppBaseから派生しているとしたときに、

auto_ptr<CApp> m_lpApp;
auto_ptr<CAppBase> m_lpAppBase;

m_lpAppBase = m_lpApp; // このスマートポインタのダウンキャストは成功するのか?

とした場合、普通のポインタ同様に使えるのならば、成功して欲しいですね。しかしよく考えると、テンプレートから派生させているので、CAppとCAppBaseとは継承関係に無いので、このダウンキャストは成功しないとも思えます。ところが、これは、(一応)成功するように設計されています。種明かしは、メンバ関数テンプレートにあります。詳しくはいまのゲームのマスターアップの後で!(笑)


第AB回 画像処理ライブラリ(マッドムービー制作への道) 00/05/16

前回書いたときからずいぶん日にちが経ったので、何書いてたか忘れました(笑) だから、もう忘れることにしましょう。前回の“種明かし”は、 Scott Meyers著『MoreEffectiveC++』にあります。この本ですが、C++中・上級者に特にお勧めです。こういうわけわからない本は会社の金で買うんですが(笑)、久々のヒットでした。

とりあえず、最近の流行の話題は、Intelの画像処理ライブラリ

http://www.intel.co.jp/jp/developer/vtune/v4/perflibst/ipl/index.htm

でしょうか。平行移動や拡大縮小回転から、離散コサイン変換(インテルの訳語では不連続余弦変換らしい)までサポートしている大規模なライブラリです。起動時に、CPUチェックを行ない、CPUごとに最適化されたDLLを読み込んでくるようで、相当なパフォーマンスが期待できそうです。(ただし、Intel製のCPUしか対応していないのが痛いか…/'00/06/16訂正 K6等にも対応しているようです) あと、各CPU用のDLLが一つにつき2MB強あるため配布はやや困難かも知れません。まあ、そこまで大規模なものを必要としないのであれば自前で作ったほうがいいような気がします。まあ、逆アセすると勉強にはなります。今後、ビデオカードの機能に頼るのではなくCPUパワーごり押しでの画像エフェクトは確実に増えてくると思います。(というか主流に成り得る可能性すらある)

ところで、最近、演出効果の参考にするため、裏サイト等で密かなブームとなりつつあるマッドムービーを見ているのですが、どうもレベル低すぎではないでしょうか。見ているのは主にLeaf系です。友人からCD−Rで10枚ぐらいもらったので順番に見てました。もちろん、これが世に流れているすべてではないでしょうけれど、全然ダメです。

まず、ゲームの素材はすべて使えるわけです。オープニングCGから、エンディングのCGまで。逆にメーカーが店頭デモを作ろうとしてもエンディングのCGを出すわけには行きません。使えるCGは、自ずと制限されています。さらに、マッドムービーの世界では(著作権的には違法ですが)曲の自由なセレクトが可能です。B’zであろうと、モーニング娘であろうと自分のイメージにあったものを選んでくることが可能です。そして、ムービーなのでFlush3などで加工が利くわけで、普通ならプログラムで書かなければならないエフェクト処理がいとも簡単に出来てしまいます。ムービーなので、多重エフェクトであろうと再生は遅くならないので、エフェクトかけ放題。残像など残し放題です。

つまり、(ゲームメーカーの人間として言わせてもらえれば)、マッドムービー制作者には非常に大きなアドバンテージがあります。それなのに、ツールの機能を組み合わせただけの作品しか出てこない。ほとんどの作品はFlush3で音に合わせて動かしてみました〜って域を逸脱しない。それが非常に残念です。

そうは言うものの、自社作品でそれを超えられるかと言うと、決してそうではない。使えるCG枚数が制限されている&エフェクトをプログラムで受け持たないといけないので大変である&納期が限られているため完成させるだけで精一杯である&音楽はイメージ通りのものは決して上がってこないという4重苦のなかで、一体何をどないせーちゅーねん!という状況が待ち構えています。つまりは勝てません(笑) だから、あんまりここでえらそーなこと書いて、「あいつの作ったゲーム買ったけど、たいしたことなかったね〜」とか言われるとぐうの音も出ないわけです(笑)

近況その2。プログラミングについて、調べるために時々検索サーバーで検索するのですが、最近、自分のサイトばっか引っ掛かって困るんです(笑) というか引っ掛かりすぎです!! 「やねうらお」で引っ掛かるのは仕方ないとして、画像とかエフェクトとかMP3とかゲーム開発とかライブラリとかDirectXとかMIDIとかエロゲーとか(笑) エロゲーで引っ掛かるのは、勘弁して〜って感じ(笑) そんなんだから「プログラミング全然わかんないけど楽しく読んでます」とか言われて、はにゃ〜ん(笑)とかなるんですよ。(少し喜んでいますが) なんだ。俺は天才プログラマーの育成のために日夜貢献しているんではなかったのかー。(それは大きな勘違いなのだ) ひょっとしてマクドナルドで友人とダベるときのためのネタ提供をしていたのか。(そうなのだ) ひょっとしてゲーセンでPop’n Music4に彼女と一緒に並んでいるときに話す話題作りに貢献していたのか。(そうなのだ) 友達んちで「夜這いマニア」をCD−Rにコ○ーする間の待ち時間に、「ねえねえこのソフト知ってる?なんでもあのやねうらおって人が作ったらしいんだけどさぁ」とか言う雰囲気作りに貢献していたというのか!(たぶん、そうなのだ) 知らなかった…。というか、最後の人、「夜這いマニア」、コ○ーせずに買ってくれよー!(笑)


第AC回 jpegの読み込みに対応させる(ついでにSusiePlug-inにも:p) 00/05/19

なんか会社の人手が足りない。死にそうである。このままではホームページの更新もままならない。(いや、ホームページは別にいいんですけどね(笑)) そんなわけで、こっそりプログラマーのアルバイトさんを募集するのだ。

職種経験年齢不問。学生可。使用言語C+++ASM(+++の部分は最大トークン法によってparsingせよ)がメイン。ターゲットはWindows/ドリキャス/プレステ/プレステ2。(どれか一つ出来れば良い) 今後はXBOXもやる。一応、オールアセンブラで(Direct3DやOpenGL等のライブラリを使わずに)3Dのゲームのプログラミングを組む程度の能力を有していて、理系の大学教養課程で学ぶ程度の数学は完璧にこなせて欲しい。4元数や行列計算も出来ない人だとちと難しい(というか全然ダメ:笑) あとFFTかDCTのプログラムぐらい組んだことが無いと話にならない。英語もオンラインマニュアルぐらいすらすら読めないと仕事にならない。ありゃりゃ。誰もいなくなっちゃったよ〜!(笑) 待ってくれ〜。おじさんが悪かったよ〜。一個や二個できなくったっていいから!少しぐらい出来なくったって誰も怒らないから!やねうらおみたく、毎日16時間仕事して8時間勉強すればいいだけの話だし!(それでは寝る時間がないんですけど…) きっと、お葬式ぐらい出してもらえるから!(いや、そうじゃなくって…) ともかく、ゲームメーカーで仕事してみたい人、募集!やねうらおにメールください。

さて本題。

その昔、VBのメーリングリストでちらっと見た覚えがあったのですが、OleLoadPictureという関数がありまして、これを使えばJPEGだってGIFだって読み込めてしまうんです。Win98以降ならば、SetDIBitsToDeviceでもJPEGは読み込めるのですが、OleLoadPictureは、なんとWindows95でも動いてしまいます。なんでこっちのAPIだけ対応してるとかしてないとかなっているのかは非常に謎なんですが(笑)

ついでに言えば、SetDIBitsToDeviceは速いんですけど、RLEやOS/2には非対応。LoadImageならばなんとかいけるんですけどね。なんで、APIごとに違うんじゃい!別の人が作ってんのかいな(笑)

いやー、その昔、MS−D○S(○は伏字。DまるSと読むこと:笑)を逆汗したことがあるんですけど、バージョンが×.×aから×.×bになるだけで内部コードがまったく異なるというー。それもコードの質が低下することもしょっちゅーという(笑) なんやー、毎回、1から別の人が組んでんのかー(笑)とか思っちゃいましたよ。

あと、yaneuraoGameSDKとygs2Kのほう、上記のOSの機能を使ったJPEG,GIF読み込みと、Susie Plug-inを利用した読み込みにも対応させたので、実装について興味のある方は、yaneuraoGameSDKのyaneSPI.hとyaneSPI.cppをご覧ください。(CPlane::LoadBitmapから呼び出しています)

GIFのほうは、特許問題がややこしいので、公式サポートとはしません。JPEGをOleLoadPictureで読もうとしたら、何故か読み込めてしまうんです。非常に迷惑です(笑) しかし、これって特許料とられるんでしょうか?一応、UNISYSには英文メールで問い合わせておきましたけど…。(JPEG読み込もうとしたら、unexpectedlyにGIFがよめちゃったけど、どうしよ〜?おっちゃんそんなん読みたかないねん!ってな内容です(笑))

そもそもyaneuraoGameSDKのほうは、プログラムではなく、サンプルソースみたいなもので、これが実際に動くわけでもないですし、これが特許料をとられるならば、OldLoadPictureの解説書いている本・WebPage等はすべて特許料を取られると思うのですが、いかがなもんでしょうか?

しかし、ygs2kのほうは、VisualC++6.0のように、コンパイラと考えれば、GIFを読み込むかどうかは、ygs2kでプログラムを行なう人が自己責任において管理すべき問題のような気もします。しかし、そう考えていくと、MicrosoftはOleLoadPictureのようにGIFを読み込めるAPIを作っているが、それに対する特許は構わないのか?という気がします。なぜ、それを利用した人間のほうが特許に抵触するのか…それも使う気もないのに!非常に謎です。ともかく、早く特許が時効になって欲しいものです。

ついでに、特定のアルゴリズムに対する特許というのはもうこれっきりにして欲しいものです。


第AD回 DLL地獄からの脱出(Windows2000の謎) 00/05/21

やねうらおの近くには生活食料品などを売っている大手スーパーのLifeというのがあります。ここ、閉店間際になると、お寿司とか値引きシールを貼っていくんですよ。どうも、おばちゃんの話によると閉店約1時間前になると100円引きのシールがまず貼られて、閉店約40分前に200円引き、そして閉店約20分前に半額のシールが貼られるらしいです。なんと、そのシールを貼るおっちゃんの跡には行列が出来るのですよ!

そんなわけで、やねうらおも閉店30分ぐらい前に行き、売り場で待機。そこには、何をするでもなしにその場をうろつく主婦たちが居るではありませんか!そう。彼女らは、半額になるのを待っているのだ…。全身から、半額になるまでは絶対買わない!という気迫がみなぎっている。やねうらおは、デジカメでその状況を撮影したかったのだが肖像権を侵害するため、イメージ図でご理解願おう。(下図)

「半額になるまでは絶対買いませんにょ」「売れ残ってめそめそ泣くがいいですにょ」などという独り言が聞こえてくるではないか。やねうらおは、えげつな〜(笑)と思っていると、向こうからやってきたよ、半額おじさん!(誰が半額おじさんやっちゅーねん…)

そのおじさんが値引きシールを貼るや否や、一気に群がる主婦たち。彼女らもやはり死活問題なのだ。やねうらおも実は、この日はちょっとおかしかった。それと言うのも、カップラーメンに押すだけポット君でお湯を入れようと思ったら、なんとコンセントがつながっていなかったために、水を入れてしまったのだ。大チョンボである。こんときだけは、押すだけポット君を恨めしそうに見つめてこう言ったよ。

お前、いつから水だけポット君になったんだよ〜!

電子レンジがあれば、このカップラーメンを電子レンジに入れるという裏ワザもあるのだが、あいにく電子レンジは無い。かと言って食べ物を粗末にしては目が潰れると親から教えられてきたやねうらおは、これを食べることにしたのだ。いやー凄く惨めな気分になったね〜(笑)

だからこそ、ここで半額の寿司を買って、この不愉快な想いを払拭したかったのだが、そのおばさんたちの早いこと、早いこと。なんで一人3パックも買うんよ!?とか思っている間に寿司は売り切れ。しかもおばちゃんたちは、もうレジまで一直線ではあーりませんか!うひょー。その姿はさながら食パンの耳に群がっていた鳩が、子供が大きな動きを見せたために一斉に飛び立ったかのようであった。おがーち゛ゃん、やっぱ東京は怖いとこだよ〜。

そうは言っても、やねうらおの実家は大阪府八尾市である。河内弁のメッカである。日本で一番口が悪い地域である。こんなところで引き下がったのではプライドが許さない。そうだ。明日は、心をヤクザにして頑張ろう。(なんのこっちゃ)

さてさて。Windows2000で、あるソフトを入れてからペイントが立ちあがらなくなったんですよ。いわゆるDLL地獄の始まりなんですが、MFC42.DLLとかMFC42u.DLLとかその手のファイル、古いバージョンのものを入れる不届きなアプリがよくあるんですよ。ついでに言えば、Windows98に新しいメディアプレイヤーを入れてからMPEG4(v3)が見れなくなってしまったのです。(新しいDLLではどうもMPEG4(v3)に対応していないようです。MPEG4(v3)は今後、無くなるからなのでしょうか?)

本当はDLLなんていらないと思うんです。よく、100個のアプリケーションがひとつのDLLを共有(して利用)することによって、ディスクのスペースの節約になっているなんてことを言う人がいますが、それがどれだけのもんですか?と言いたい。DLLは何もかも入っているので大きいですが、実際に一つのソフトが使っている部分ってのはその10分の1ほどしか無いわけで、最近のコンパイラならたいていスマートリンクするため、呼び出していないライブラリ等は実行ファイルから削がれるわけです。しかも、使いもしないVisualBasicのDLLも山のように入っています。つまり、DLLなんて無くったって何も困らないし、容量だってほとんど節約になっていないのがWindowsでのDLL利用の実態なのです。

同じDLLを使う2つのアプリケーションを使えばメモリの節約になるなんてことを言う人がいますが、そんな機会がどれだけありますか?と言いたい。それより馬鹿でっかいDLLをメモリ上に読み込むことのほうが大きな負担になっています。

そんなDLLですが、すべてWindowsのシステムフォルダに入るので、どれがシステムので、どれがサードパーティのか分別不能です。特にフリーウェアの作者とかはインストーラー手を抜くから、日付チェックせずにDLLを強制上書きして壊したい放題。さすがにそれが顰蹙だったのか、Windows2000ではSYSTEM32にあるDLLはバージョンチェック機構らしきものが付いているようですが…。

それと言うのも、壊れたペイント(mspaint.exe)を復帰させるために別のパソコンからMFC42u.dllだけコピーしてきたのですが(共有違反でコピーできないときは、コピー先のMFC42u.dllのファイル名を変更したのちに、コピー元からMFC42u.dllをコピーして再起動する)、何かの弾みに、元のファイルに戻ってしまうのです。なんでまた壊すね〜ん!とか思ったのですが、どうやら、SYSTEM32の中にある隠し属性のdllcacheフォルダの中身と比較してタイムスタンプが古ければ、新しいほうに書き換えるようです。(よく確認していないので違ったら、すんません)

ということは、いつの間にか、dllcacheのほうのファイルを古いバージョンに書き換えてた悪い奴がいるはずなんですが、それが何だか特定できません。かなり困った奴です。おそらくMircosoftの製品のような気がするのですが(笑) 自社製品との相性さえ良くない会社のOS使ってて、この先、大丈夫なんか〜とか思いますけどね(笑) たぶん、大丈夫ではないのでしょう…。嗚呼。早くこんな生活から抜け出したいなぁ…。


第AE回 C++テンプレートの意義(スマートになろうぜ!) 00/06/10

やねうらおは、考えごとしながら歩いていると、そのまま迷子になります。方向音痴というわけではないのですが、視力が悪いため遠くのものが見えません。目印と言えば、電柱とかマンションとかそういうのしか無いわけです。先日も、弁当を買いに行くと言って会社を出たまま考えごとしながら歩いていたら、そのまま迷子になり、まあいいか〜とか思いながらそのまま歩きつづけること3時間。(勤務時間中だってのに…)

電車の線路すら見当たらないので、さすがにこれはやばいだろうとか思って、サンクスで『マップル』(地図)を買って、なんとかもよりの駅に到着。切符買うときに運賃表を見て唖然。帰るべき中河原駅が無いよ〜。いやー、ここどこなんよー。マップルで確認。どうやら、路線を乗り継いで帰らなければならないようだ。駅にして9駅ある。しまったよ。弁当代しか持ってきてなかったのに、マップル買ったからそんな金ないよ(笑) 帰れないよ〜。結局、帰れるところまで電車に乗って途中の駅で降りてそこからマップル見ながら歩いて帰ったんですよ。

会社にようやく辿りつくと、やねうらおは逃げたんではないかと大騒ぎになっている。いや、逃げてないんですよ。ちょっと弁当買いに行ってたんですけど、迷子になって。だからメシまだ食ってないんですよ。えへへ。< えへへじゃないって…

お子ちゃまじゃないんだから…などとみんなにボロクソ言われながらも、とりあえず一件落着。(?) このあと東京で何度迷子になるのかはわかりませんが、願わくはマップルは3冊までにしたいものです(笑)

ところで、みなさんC++のテンプレートって使ってますか?テンプレートはサイズがでかくなるから、嫌いだって言う人も多いですが、搭載メモリも増えているので、今後、それはそれほどWeekPointにはならないような気がします。テンプレートのメリットは、静的にバインディングされるため実行効率が良いことではなく、C++やJavaのように強く型付けされた言語において、直交性を持った設計が出来ることでしょう。(注:Javaにはテンプレートは有りません。これは、ある意味、致命的なことかも知れません)

そんなテンプレートですが、どうしてあんなにサイズがでかくなるんでしょうか?今回は、それを考えてみたいと思います。

STLのlistが遅いとさ〜さんと言っていたのですが、それは、STLのlistは双方向ポインタ(逆反復子を導入するのを念頭に置くため)になっているのも、効率を下げる原因にあるのではないかと思ったのです。そこで、単方向のlistをテンプレート(以下CList)で実装してみようかと思ったわけです。あるクラスへのポインタが何バイトになるのかは実装系依存(VC++6.0についてならば第94回を参照のこと)ですが、いま仮に、すべて4バイトだとしたらどうでしょうか?

CList<int*>::add_last関数とCList<LPSTR*>::add_last関数とでは、まったく同じコードが生成されるはずです。ところが、呼び出していない関数は削除してくれるVC++6.0のスマートリンカをもってしても、この共通項が括られることは無く、実行ファイル上には、同じコードを持った別名の関数が、2つ存在することになります。これがテンプレートでプログラミングしたときに、実行ファイルがやたらと増大する原因のひとつだと私は考えています。特にテンプレート関数はその性質上、展開されるコードがほぼ同一になることも少なくないので、そういうのは共通項として括り出すような機能をリンカに用意するか、コンパイル段階で括り出すべきなのです。せめて、コンパイルオプションで、そういうのがあってもいいと思うのですが、どうでしょうか。

ありそうで誰も言わなかったアイデア(当たり前すぎて言わないのか…)だと思うのですが、VisualStudio7.0のほうの要望としてMircosoftに投書してみようと思います。もし、現状のVC++6.0等でコンパイルオプションで出来るならば、やねうらおが大恥をかく前に教えていただけると幸いです。^^


第AF回 STLは遅くない(らしい) 00/06/12

昨日、さ〜さんが遊びに来て、STLは本当に遅いのか?という問題について、少し議論したので報告します。

さ〜「std::listの実装が双方向ポインタであることは関係ないと思うんですよ。イテレータで巡回するときに遅いわけですから」

やね「そうですね。実験で比較したときの要素は、いくらでしたっけ?」

さ〜「1000ぐらいだったと思いますが」

やね「んっ!?1000ですか?双方向ポインタになっているということは少なくともサイズは8バイトありますよね。1000あったら、8Kなので、すべての要素がL1キャッシュ(実験に使っていたMMXマシンでは8K)に入りますか?」

さ〜「あっ。そうか!いけてねぇ(笑)」

やね「ホームページのほうどうしましょうか^^」

さ〜「知らぬ存ぜぬで押し通しましょう(笑)」

というような充実した議論(どこがや)の結果、STLはやっぱそれほど遅くないのではないか?という結論に至ったのでした。

しかし、メモリ転送のベンチマークとかで、L1キャッシュの存在を無視したものがありますが、あれははっきり言ってマヌケ以外の何者でもありません。L1キャッシュに載っていれば、ノンウェイトでデータが得られるのに対して、L2および外部にあるものは、その何倍も遅いのですから!(ちなみに最近のプロセッサとして、PentiumIIIでは、L1キャッシュは32Kで、K6-IIIで64K、Athlonで128Kです) とは言え、今回のようなミスを犯していたのでは、私たちとて人のことを笑ってはいられませんね^^

STL疑惑も解けたことなので、みなさん積極的にSTLを使いましょう(笑)


第B0回 ウィルスバスターは、ウィルスか(も知れない^^) 00/06/13

Windows2000に変えてから良く止まる。(Visual C++の)Debugモードでステップトレースしていて止まるのはなんでやねーん!とか思って、知り合いに尋ねたら、「ウィルスバスターのリアルタイム検索をオンにしてないかと」いや、してるよ。ウィルス付きソフトなんて出したらシャレなんないもん。「それをいますぐ切れ」と。いますぐ切れって…なんで?と思いながら、オフにすると確かにDebug中にフリーズする現象は無くなった。

なんや?ウィルスバスターはウィルスなんか?

そういや彼とは昔、CMのことで盛り上がったことがある。テレビを一緒に見ながら突っ込みを入れるのだ。的確な突っ込みを入れたほうが勝ちなのだ。^^

それは、「mother、mをとったら?other他人です」という家庭教師のトライのCMが流れたときのことだった。

「お前、otherは他人じゃねーだろよぉ?」

と彼は強烈な突っ込みを入れた。英語に詳しくなくて彼の突っ込みが理解できない人は、是非辞書を引いて確認していただきたい。

otherは単独で代名詞としての用法はない。other peopleのようにして形容詞として名詞を修飾する用法があって、そこから派生した代名詞の用法としてothersと複数形ならば「(2つのうちで)もう一方の人」、「(3つ以上のうちで)それ以外の人たち」を意味することはあるが、other単独ではそのような意味にならない。

おまけに、othersであったとしても、そこには「他人」というような意味はない。日本語の他人というと、それは自分と関係のない人の意味だが、othersは排他的人称代名詞(やねうらお造語)で、「それ以外の人たち」というニュアンスである。(日本語の「他人」と意味的に重なる部分はあるが)

つまり、CMで嘘を教えるな!であって、おまけにそれが教育関係のCMなんだから、救いようがない気がする。何万人という人が見ているのに、堂々と嘘を言うな!である。いや、それって、このホームページも該当するのでは…以後、気をつけます(笑)


戻る