「メモリが "read" になることはできませんでした。」の謎。

question:1103246823

 このエラーが出るのは許可された範囲外のメモリを読み/書きしようとしたからで、はっきり言ってほとんどの場合は原因不明。まあプログラム自体のバグで特定の操作をしたときに計算結果がおかしくなって範囲外にアクセスしてしまうこともあるかもしれないけどたぶんそれは希。バックでかなり沢山のプログラムが動いているからそれらが複雑にからみあってそれが元でおかしくなっているのが普通。

 で、これから書くのは対処法とは無関係の話で、この珍妙な日本語は一体なんなのかということについて。

 Windowsを使っている人なら誰もが一度は遭遇したことがあるだろうこのメッセージ。

"0x00000000" の命令が "0x00000000" のメモリを参照しました。メモリが "read" になることはできませんでした。

 メモリがreadになることはできませんでしたって…。最初は誤訳だと思ってこの翻訳を担当した人は何を考えてるんだと思っていたんだけど、これには理由があるらしい。

 詳細については「"read" になることはできませんでした」のひみつを見てもらうことにするが、ここには次のように書いてあった。

・これらの文字列は、C 言語の printf 形式のフォーマット文字列であり、 両方とも %lx と %s という二つの変換子を含む。
・この二つの変換子の登場する順番は同じである。
・"read" や "written" はカタログ化されていない。

 このボックスに表示される文字列はntdll.dllに書かれているらしい。英語版では

The instruction at "0x%08lx" referenced memory at "0x%08lx". The memory could not be "%s".

 となっていて、日本語版では

"0x%08lx" の命令が "0x%08lx" のメモリを参照しました。メモリが "%s" になることはできませんでした。

 となっている。ここでさっき引用した部分に書いてあった事が関係してくる。

 プログラムにしてみると次のような感じだろうか。ただしCしか知らないしもう10年ぐらいはCから離れているため間違いは勘弁。コンパイラも通してないし。

char *szMemErrStr = "The instruction at \"0x%08lx\" referenced memory at \"0x%08lx\". The memory could not be \"%s\".";

void outErrorMessage(long lInstAddr,long lMemAddr,char*szOp)
{
	printf(szMemErrStr,lInstAddr,lMemAddr,szOp);
}

 まあこれじゃあコンソールに表示されるだけだしこんな馬鹿な書き方はしていないだろうけど…。で、呼び出し部分。まあエラーが発生したとき、ってことで。

	// lInstAddr lMemAddr にそれぞれの値が入っていると仮定して
	outErrorMessage(lInstAddr,lMemAddr,"read");

 これで例のメッセージが表示される。はず。

 ここで問題なのは、翻訳担当者には、上の例でいうところのszMemErrStrの内容を書き換える権限しかなかったということ(あくまで想像ではあるけれど)。と言うことは変数の登場する順番を変更することはできないし、さらにアドレスは問題ないが、読み出し、書き込みのどっちでエラーが発生したかを示す "read" "written" の文字列をそのまま使わなければならなかった。

 この様な状況であったため、冒頭に書いたような見る側からすればどうしてそうなったのかがさっぱりわからない変な日本語が登場したということになる。

 担当者にしてみても、ほんとはここは「メモリを読めませんでした」とか「メモリに書き込めませんでした」と書きたかっただろうけれども、なんとかどこかでreadもしくはwrittenを使う文字にしようと頭をひねった苦肉の策らしいのだ。

 というわけで、これからこのメッセージを見かけたら、どうか暖かい目で見守ってやってほしい。こうするしか他に手がなかったのだから。