a == b == c
ふと目にしたCのコードでa == b == c と書いてある箇所を目にしてこれコンパイルできるのかなと思ってやってみるとコンパイルできたので見てみた。
yoshimi% cat test.c #include <stdio.h> int main () { int a, b, c; a = 0; b = 0; c = 0; if ( a == b == c ) { printf("passed!!\n"); } else { printf("not passed!!\n"); } }
yoshimi% cat test2.c #include <stdio.h> int main () { int a, b, c; a = 0; b = 0; c = 0; if ( a == b && b == c ) { printf("passed!!\n"); } else { printf("not passed!!\n"); } }
test2はpassするが、testは通らないので、 優先順位として、( a == b ) == cと解釈されてるっぽい。
アセンブラにしてみるとどうだろうということで見てみた。ちなみに、gcc -S test.cでtest.sという名前でアセンブラにしてくれるらしい。diffを取ってみるとわかりやすい。
yoshimi% diff -u test*.s --- test.s 2009-03-31 01:43:33.000000000 +0900 +++ test2.s 2009-03-31 01:43:20.000000000 +0900 @@ -10,28 +10,28 @@ movl %esp, %ebp pushl %ebx subl $36, %esp - call L7 + call L8 "L00000000001$pb": -L7: +L8: popl %ebx movl $0, -20(%ebp) movl $0, -16(%ebp) movl $0, -12(%ebp) movl -20(%ebp), %eax cmpl -16(%ebp), %eax - sete %al - movzbl %al, %eax + jne L2 + movl -16(%ebp), %eax cmpl -12(%ebp), %eax jne L2 leal LC0-"L00000000001$pb"(%ebx), %eax movl %eax, (%esp) call L_puts$stub - jmp L6 + jmp L7 L2: leal LC1-"L00000000001$pb"(%ebx), %eax movl %eax, (%esp) call L_puts$stub -L6: +L7: addl $36, %esp popl %ebx leave
アセンブラはまじめに勉強したことがないのでほとんど読めないですが、これぐらいの量なら頑張れそうなので、勉強してみるかなぁ。
一応どういう挙動になるなのかの予測はついてるのでそれに基づいて各命令の意味を調べてくだけでもいい勉強にはなりそう。
test.cを以下のように変更して、アセンブラのコードでdiffをとってみると、
yoshimi% diff -u test.c test3.c --- test.c 2009-03-31 01:32:39.000000000 +0900 +++ test3.c 2009-03-31 02:19:50.000000000 +0900 @@ -7,7 +7,7 @@ b = 0; c = 0; - if ( a == b == c ) { + if ( ( a == b ) == c ) { printf("passed!!\n"); } else { printf("not passed!!\n");
差がないので、とりあえず予測が正しいということは裏付けがいちおう取れたっぽい。
もちろん-Wallでコンパイルすれば以下のように警告がちゃんと出るので、
test.c:10: warning: comparisons like X<=Y<=Z do not have their mathematical meaning
まぁふつうはこんな書き方されないですよね。きっと。