トップ «前の日記(2008-04-08) 最新 次の日記(2008-04-10)» 編集

日々の破片

著作一覧

2008-04-09

_ Ruby Way

翔泳社さんに献本していただきました。

Ruby Way 第2版 (Professional Ruby Series)(Hal Fulton)

ハルフルトンのRuby Wayの第2版です。網羅的で、確かに決定版のひとつかな。

イディオムあたりを含めて、最初にRubyってこんな言語というのを説明したあとに、怒涛のように、文字列、正規表現、国際化、数値計算、……IO、動的機能、スレッド、……テスト、デバッグ、パッケージ化(RubyGemとかRDocとかRubyForgeとか)、ネットワーク、Webあたり、dRubyととにかくいろいろまとまっているので、便利かな。印象としては、プログラミングWindowsという感じ。Advanced Windowsではなくて。つまり、リクターではなくペトゾルド。つまり、手元に一冊、職場に一冊、どちらかというと仕事プログラミング用、という感じかな。デイブトーマスのより、1冊にまとまっているのが良い点かも。

あと、国際化のあたりを読むと、原書を更新して1.9についても触れています。その代わりGUIのあたりを少し落としたようです(原書はみていないので、どのあたりを落としたのかはわからないけど)。確かに、謝辞にはGetTextだけではなく、GTKについてもむとうさんが協力してくれたとか書いてあるけど、GTKは落ちているようです(索引と目次のレベルでは)。

なんで、これの初版は売れなかったんだろう(Ruby Wayが売れなかったということは伝説的に語られているので、たぶん、売れなかったらしい)と、疑問に感じるのは、きっと表紙の暗さのせいかも。それが理由だったら、この第2版はいけるんじゃないかな、僕は良い感じだと思う。

ちなみに、こっちは初版の翻訳。

The Ruby Way―Ruby道への招待(ハル フルトン)

第2版が出た以上、Ruby 1.6(だと思う)を使うというような理由がない限り、歴史的な本かな。

_ VC謎動作

先日の別の関数でポインタを初期化するというネタですが、素直に考えれば、

void foo() {
    int b = 0;         ////////////// 何これ?
    char* a = "hello world !";
}
void bar() {
    int b = 0;         ////////////// 何これ?
    char* n;
    printf("%s\n", n);
}

と疑問に感じるはず。でも、理由はわからないんだよね。

とはいえ、疑問を表明している人もいたので、わかることは書いておく。

理由には2つあって、あのプログラムで余分な自動変数が必要な理由と、なぜコンパイラ(VC++。gccは素直なコードを吐くのでint b = 0;は不要)がそうするのかという理由、のうち後者のほうが、わからない。

前者の理由は、次のアセンブリ出力を見るとわかる。

; File c:\test\hello.c
; Line 3
	push	ebp
	mov	ebp, esp
	push	ecx            ← 4バイト確保するため(ecxの保存のためではない)
; Line 5
	mov	DWORD PTR _a$[ebp], OFFSET $SG2456

これは、int b = 0;の行を削除した場合のfooのコード。aのための領域の確保になぜかecxのpushを使っている。この後popはしないので(当然のようにmov esp, ebpする)これは、単にspを4バイト進めたい(戻したい)だけとしか思えない。確かにこの方法でもスタックに4バイトが確保できるけど。

この方法で自動変数を確保されると、barを呼んだ時に、nがその時点のecxの値で初期化されてしまって、せっかくfooで設定した値が消えてしまう。

一方、int b = 0;を入れると、次の出力を得る。

; File c:\test\hello.c
; Line 3
	push	ebp
	mov	ebp, esp
	sub	esp, 8           ← 8バイト分を確保
; Line 4
	mov	DWORD PTR _b$[ebp], 0
; Line 5
	mov	DWORD PTR _a$[ebp], OFFSET $SG2457

と、単にespを進める(戻す)だけなので、fooで設定した値がbarで利用可能。

この動作はなぞで、手元のi386のリファレンスを見たけど、レジスタpushは7サイクル、直値のレジスタaddは2サイクルなので、速度の問題とは思えない。とはいえ、i386は古すぎるので、インテルのサイトでi686のデータシートを調べたけど、インストラクションセットにサイクル数とか出てなくてわからなかった。でも、スタックへ積むというのはメモリアクセスが必要なので(即値はコードキャッシュへフェッチ済みなのでどう考えてもスタックpushより遅いとは思えない)仮に686あたりで変わるとも思えない。

というわけで、余分な自動変数を付けたのでした。

追記:速度しか考えていなかったけど、push ecxは0x51、それに対してsub esp, 4は0xec 0x04で、サイズが小さいというメリットがあって、それを優先したのかも。8バイトの確保になると、サイズが同じになって速度的なデメリットだけになるので、pushをやめるということかも。


2003|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|

ジェズイットを見習え