#include <stdio.h>
#define PRINT_X printf("%d\n",x)
int main(void)
{
int x=2, y, z;
x *= 3 + 2;
PRINT_X; // 演算子 2.1
x *= y = z = 4;
PRINT_X; // 演算子 2.2
x = y == z;
PRINT_X; // 演算子 2.3
x == ( y = z );
PRINT_X; // 演算子 2.4
return 0;
}
このプログラムですが、私の環境でコンパイルすると演算子2.4の部分で下記のワーニングがでます。
「等価比較の結果が未使用」、「この等価比較を代入にするには '=' を使用します」と言われてしまいますが、意図的に '==' を使用しているはずですので、ここでは無視します。
c:\Users\xxx\Documents\C\operators_2.c:21:7: warning: equality comparison result unused
[-Wunused-comparison]
x == ( y = z );
~~^~~~~~~~~~~~
c:\Users\xxx\Documents\C\operators_2.c:21:7: note: use '=' to turn this equality comparison into an assignment
x == ( y = z );
^~
=
ここから解説です。
まずは冒頭 define です。
#define PRINT_X printf("%d\n",x)
これはコンパイルの前処理で PRINT_X が printf("%d\n",x) に置き換えられます。
演算子 2.1
初期値: x = 2
x *= 3 + 2
x *= (3 + 2) ---(1)
(x *= (3 + 2)) ---(2)
(x *= 5)
(x = x * 5) ---(3)
(x = 2 * 5)
x = 10
(1)演算子の優先度が高いのは +
(2)次に *=
順に計算していきます。
(3)*= は、演算子の左側の値と右側の値を掛け算して、その結果を左側に代入します。
演算子 2.2
初期値: x = 10(演算子2.1の結果より)
x *= y = z = 4
x *= y = (z = 4) ---(1)
x *= (y = (z = 4))
(x *= (y = (z = 4))) ---(2)
(x *= (y = 4))
(x *= 4)
(x = x * 4)
(x = 10 * 4)
x = 40
※ y = 4, z = 4
(1)*=, = の優先度は同じです。結合法則は右から左なので右から順に( )で括っていきます。
(2) ( )で括ったらあとは順に計算していきます。
演算子 2.3
初期値: x = 40, y = 4, z = 4(演算子2.2の結果より)
x = y == z
x = (y == z) ---(1)
(x = (y == z)) ---(2)
(x = (True)) ---(3)
x = 1
(1)優先度が高いのは等価演算子(==)。
(2)次に = 。
(3)y == z は True(真)となります。(初期値: y = 4, z = 4)
Trueの場合の値は規格上は非0(0以外)ですが、多くのコンパイラでは1になります。
演算子 2.4
初期値: x = 1, y = 4, z = 4(演算子2.3の結果より)
x == ( y = z )
(x == (y = z)) ---(1)
(x == 4)
(False) ---(2)
(0)
x = 1 ---(3)
(1)演算子の優先度は == の方がうえですが、( )内が優先されるので y = z の演算が先。
(2)x == 4 は、x の初期値が1なので False(偽)となります。
Falseの場合の値は 0 になります。
(3)x == 4 の評価の結果は 0 ですが、評価結果をxに代入していないので x の値は変わらず 1 です。
(右上の + マークをクリックすると解説が表示されます)
※実行環境 clang version 14.0.6 Target: x86_64-pc-windows-msvc
コメント