トップC言語入門 > C言語の文法(1)

C言語の文法(1)

C言語の文法にまつわる話をひとつ、ふたつ。

1.結合性

C言語の演算子一覧表を見ると、結合性の欄がある。 加減乗除演算子(+, -, *, /)や比較演算子(関係演算子)(>, >=, <, <=)などは「左結合」である。 例えば、x = a + b + c のように、同じ+演算子が二つ以上続いた場合、 左にある+を先に計算するというのが、「左結合」である。 つまり、a + b を先に計算し、その結果に c を足したものが x になる。 ( )を使うと、x = (a + b) + c と表される。

比較演算子(関係演算子)も同じ左結合だということは、 a < b < c は (a < b) < c だということになる。 数学で a < b < c と書けば、「a < b かつ b < c」 であるから、 C言語の文法と数学の文法は異なることに注意がいる。 数学での a < b < c はC言語では a < b && b < c と書かねばならない。

次のプログラムをTCCでコンパイルしてみよう。

void func(int k) {
    int m = 3 + 4 + 5;
    int n = k + 6 + 7;
}
void main() { func(1); }

func関数のコードは次のようになる。

00401000 55                     push    ebp
00401001 89E5                   mov     ebp,esp
00401003 81EC08000000           sub     esp,8
00401009 90                     nop
0040100A B80C000000             mov     eax,0Ch
0040100F 8945FC                 mov     [ebp-4],eax
00401012 8B4508                 mov     eax,[ebp+8]
00401015 83C006                 add     eax,6
00401018 83C007                 add     eax,7
0040101B 8945F8                 mov     [ebp-8],eax
0040101E C9                     leave
0040101F C3                     ret

3 + 4 + 5 はコンパイラが計算してその結果12(16進表示で0Ch)を変数 m にセットしている。 すなわち、次のプログラムとおなじコードが生成される。

void func(int k) {
    int m = 12;
    int n = k + 6 + 7;
}

コンパイラが気の利いたことをするのなら、なぜ、6 + 7 の計算も行って、

void func(int k) {
    int m = 12;
    int n = k + 13;
}
としないのか? その理由は、左結合規則では、k + 6 + 7 は (k + 6) + 7 である。 k が変数であるから、k + 6 は変数であり、これ以上簡単にならない。 数学ならば、 n = k + 6 + 7 は n = k + 13 と等価であるが、 C言語では、文法上、両者は等価でない。 (実行結果は多分一致するであろう。不一致のケースがちょっと思いつかない。 しかし、コンピュータのハードウェアに依存して、不一致のケースがあるやも知れない。)

2.論理値

C言語では、通常、真を1、偽を0とする。最新のC言語の文法を確認していないが、 昔、真を -1 としていたものがあったことを記憶している。 −1は2進表記では、11…1 であるから、理にかなっている。 if (n) のような場合、n == 0 の場合のみ、偽で、その他の場合は真扱いとなるため、 C言語における論理値にはどこかあいまいさがある。