2008/06/13
久々にCで面白いバグ(解答篇)
昨日の書き込みの解答篇です。
バグのあるコードを再掲します。
// buggy code *(const char**)apr_array_push(arr) = arr->nelts == 0 ? "foo" : "bar";
ヒントに示したK&R2の65ページには次のように書いてあります。
多くの言語と同様に、Cでは演算子の被演算数に対する評価順序は指定していない。(例外は、&&、?:と','である。)
代入演算子(=)の右辺と左辺のどちらを先に評価するかが決まっていません。バグのあるコードの場合、右辺を先に評価すると、一回目にarr->nelts==0が真になり、意図どおりの動作をします。左辺を先に評価すると、apr_array_push()の中でarr->neltsをインクリメントするため、意図どおりにarr->nelts==0が真になることはありません。
少し続きがあります。ヒントのひとつとして次のように書きました。
Javaでは(残念ながら)同じバグを起こせません
Javaは被演算数に対する評価順序を「左から右」と規定しています。しかし、本質的なバグの原因(式の中の副作用)がなくなるわけではありません。誤ったヒントでした。
Javaでも同様の問題があることをコード例で示してみます。Cのコードと似たようなコード(副作用のある式。メソッド呼び出しを含む左辺値を返す式)にしてみました。Cですら不格好なのに、Javaにすると嫌がらせとしか思えません。と言うか、Javaの方が分かりづらい気すらします。
class My { // Note that this is not a productive code private String[] arr = new String[32]; private int nelts = 0; public String[] arrPush() { nelts++; return arr; } public static void main(String args[]) { My my = new My(); my.arrPush()[my.nelts] = my.nelts == 0 ? "foo" : "bar"; } }
- Category(s)
- カテゴリなし
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/inoue/c-bug-answer/tbping