B.演算子
Copyright(C) 13Jan2003 coskx
演算子についての説明である。内容は以下のとおりである。
1.C言語における算術演算子
2.C言語におけるビット演算子
3.C言語における条件の表現
4.sizeof演算子
APPENDIX 1 BOOL演算
APPENDIX 2 演算子の優先順位
B.1 C言語における算術演算子 |
---|
算術演算子
演算子 |
意味 |
= |
左辺の値を右辺の変数に代入する |
+ |
加算 |
- |
減算 |
* |
乗算「×」 |
/ |
除算「÷」 |
% |
剰余(割ったあまりを求める) 整数演算のみ有効 例 a%b aをbで割ったあまりを求める演算 |
++ |
「a++」「++a」は「a=a+1」と同じ |
-- |
「a--」「--a」は「a=a-1」と同じ |
+= |
「a+=b;」は「a=a+b;」の意味 |
-= |
「a-=b;」は「a=a-b;」の意味 |
*= |
「a*=b;」は「a=a*b;」の意味 |
/= |
「a/=b;」は「a=a/b;」の意味 |
%= |
「a%=b;」は「a=a%b;」の意味 |
加減乗除の優先順位
加減乗除の優先順位は算数の常識と同じであり,乗除が優先し加減はその後である。 例 100/2*3
→(100/2)*3 →50*3 →150 |
整数(小数点のない数,intなど)と実数(小数点以下がある数,doubleなど)の混合演算
演算は優先順位にもとづいて順番に実行されるが, 例 変数を用いた例 cast演算(型変換演算)の例 |
++,--について
「++」「--」は,変数の前に置かれた場合は前置演算子,変数の後に置かれた場合は後置演算子と呼ばれる。 例 後置演算子 後置演算の意味
前置演算の意味
例
|
等号についての補足(中級者向け説明)
「a=b;」は「bの値をaに代入する」という意味であった。 ところでC言語では式「a=b」そのものが値を持ち,「c= (a=b)」が意味を持つ。『「a=b」そのものの値』とは「左辺に代入された値」のことである。すなわち,「c=(a=b)」では,まず始めにbの値が aに代入され,次に『式「a=b」の値』(それはaの値)がcに代入されるということになる。次のプログラムの実行状況を追跡するとこのことが確認でき る。
|
B.2 C言語におけるビット演算子 |
---|
ビット演算は整数型変数(char型,int型など)に対して行なわれる演算である。変数のビットパターンに対する演算である。
(1)シフト演算
演算子
意味
<<
左シフト
>>
右シフト
この演算は,整数におけるコンピュータの内部表現において,右や左にずらす演算である。(もともとコンピュータ内部で数値は,2進数で扱われているビットパターンである)
例えば
「12<<3」は12を左に3つずらす意味であり,12はビットパターンで表すと「1100」なので左に3つずらすと「1100000」となりこれは96である。
「12>>2」は12を右に2つずらす意味であり,12はビットパターンで表すと「1100」なので右に2つずらすと「11」となりこれは3である。
一般に整数を左に1つずらすと2倍になり,2つずらすと4倍になり,3つずらすと8倍になり4つずらすと16倍になる。逆に右に1つずらすと1/2倍になり,2つずらすと1/4倍になり,3つずらすと1/8倍になり,4つずらすと1/16倍になる。
例
int x,y;
の時
y=x/1024;
と
y=x>>10;
は同じ意味になる。
(2)論理演算
演算子
意味
&
2つの値のビットごとのand演算
|
2つの値のビットごとのor演算
^
2つの値のビットごとのxor演算(排他的OR)
~
ある値の全ビット反転
例 「157&241」はビットパターンでは「10011101&11110001」となり,以下のように結果は10010001すなわち145となる1001 1101
& 1111 0001 ビットごとに縦にアンド演算を行う。繰り上がり繰り下がりはない。
-------------
1001 0001
もし
int x=157;
int y=241;
int z;
なら
z=x&y;
の演算で,zには145が代入される。
2進法表現
16進法表現
10進法表現
第1変数
1001 1101
9D
157
第2変数
1111 0001
F1
241
結果
1001 0001
91
145
例 「157|241」はビットパターンでは「10011101|11110001」となり,以下のように結果は11111101すなわち253となる
1001 1101
| 1111 0001 ビットごとに縦にオア演算を行う。繰り上がり繰り下がりはない。
-------------
1111 1101
もし
int x=157;
int y=241;
int z;
なら
z=x|y;
の演算で,zには253が代入される。
2進法表現
16進法表現
10進法表現
第1変数
1001 1101
9D
157
第2変数
1111 0001
F1
241
結果
1111 1101
FD
253
例 「157^241」はビットパターンでは「10011101^11110001」となり,以下のように結果は01101100すなわち108となる
1001 1101
^ 1111 0001 ビットごとに縦に排他オア演算を行う。繰り上がり繰り下がりはない。
-------------
0110 1100
もし
int x=157;
int y=241;
int z;
なら
z=x^y;
の演算で,zには108が代入される。
2進法表現
16進法表現
10進法表現
第1変数
1001 1101
9D
157
第2変数
1111 0001
F1
241
結果
0110 1100
6C
108
例 「~157」はビットパターンでは「~10011101」となり,以下のように結果は01100010すなわち98となる
~ 1001 1101 ビットごとに反転演算を行う。繰り上がり繰り下がりはない。
-------------
0110 0010
もし
unsigned char x=157;
unsigned char z;
なら
z=~x;
の演算で,zには98が代入される。
2進法表現
16進法表現
10進法表現
第1変数
1001 1101
9D
157
0110 0010
0
62
98
使用例
int k;
のもとで
if (k%256==0) {
は
if ((k&0xff)==0) {
と同じ意味になる。2のべき乗の時のみ使える
int k,k1,k2,k3;
のもとでk1=k2=k3=0;
for (k=0; k<10000; k++) {
k1++;
k1&=3;
k2++;
k2&=7;
k3++;
k3&=0xf;
:
:
}
では
k1の値は0,1,2,0,1,2,0,1,2,・・・
のように0,1,2を繰り返し,
k2の値は0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,0,1,2,3,・・・
のように0,1,2,・・,7を繰り返し,
k3の値は0,1,2,3,・・,13,14,15,0,1,2,3,・・,13,14,15,0,1,2,3,・・,13,14,15,0,1,2,3,・・
のように0,1,2,・・,13,14,15を繰り返す。
unsigned int x:
のもとで,if (x&1==1) はxの第0ビット(右端)が1だったらの意味になる.
if (x&2==2) はxの第1ビット(右から2番目)が1だったらの意味になる.
if (x&4==4) はxの第2ビット(右から3番目)が1だったらの意味になる.
if (x&8==8) はxの第3ビット(右から4番目)が1だったらの意味になる.
if ((x&0x10)==0x10) はxの第4ビット(右から5番目)が1だったらの意味になる.
(3)ビット演算子利用上の注意
ビット演算子の優先順位は低いので「()かっこ」を利用しておくとよい。
例 int k1,k2 のもとで
k2=k1<<4+1;
はそのままでは
k2=k1<<(4+1);
のように解釈される。もし
k2=(k1<<4)+1;
の記述をしたければ,そのように書く必要がある。同様に
if (k2==k1&0xff) {
はそのままでは
if ((k2==k1)&0xff) {
のように解釈される。もし
if (k2==(k1&0xff)) {
の記述をしたければ,そのように書く必要がある。
(4)「ビット演算子」+「=」
ビット演算子においても「&=」などの表現ができる。
文
意味
x <<= 3;
x = x<<3;
x >>= 4;
x = x>>4;
x &= 0xf;
x = x&0xf;
x |= 0x55;
x = x|0x55;
x ^= 0xffff;
x = x^0xffff;
左シフト「<<」は1つシフトする毎に2倍される。signed変数では負の値である場合もあるが,
その場合でも1つシフトする毎に2倍される関係は保たれている。
unsigned変数では,変数の最上位ビットを越えるとオーバーフローして正しくない値になる。
signed変数では最上位ビットが符号ビットとなっているため,最上位ビットが変化する場合には,
オーバーフローして正しくない値になる。
signed short int (16bit)の場合の例
演算
x
y
y= x<<2
5 (101)
-5 (1111 1111 1111 1011)
28672 (0111 0000 0000 0000)
20 (1 0100)
-20 (1111 1111 1110 1100)
-16384 (1100 0000 0000 0000) OF
unsigned short int (16bit)の場合の例
演算
x
y
y= x<<2
5 (101)
14336 (0011 1000 0000 0000)
28672 (0111 0000 0000 0000)
20 (1 0100)
57344 (1110 0000 0000 0000)
49152 (1100 0000 0000 0000) OF
右シフト「>>」は1つシフトする毎に1/2倍される。signed変数では負の値である場合もあるが,
その場合でも1つシフトする毎に1/2倍される関係は保たれている。(最上位ビットが残される)
-1を1つシフトしても値は変わらない。
signed short int (16bit)の場合の例
演算
x
y
y= x>>2
20 (1 0100)
-20 (1111 1111 1110 1100)
-8192 (1110 0000 0000 0000)
-1 (1111 1111 1111 1111)
5 (101)
-5 (1111 1111 1111 1011)
-2048 (1111 1000 0000 0000)
-1 (1111 1111 1111 1111)
unsigned short int (16bit)の場合の例
演算
x
y
y= x>>2
20 (1 0100)
57344 (1110 0000 0000 0000)
5 (101)
14336 (0011 1000 0000 0000)
B.3 C言語における条件の表現 |
---|
数学で「a≦b」と表現される関係をC言語では「a<=b」と書く。同様な表現を以下の表に示す。 次のような使われ方をする。 while (a<=b) if (a<=b) while((b<a)&&(a<c)) | ||
数学の表現 | C言語の表現 | 意味 |
a=b | a==b | aとbが等しい |
a<b | a<b | aはbより小さい |
a>b | a>b | aはbより大きい |
a≦b | a<=b (a=<b は誤り) | aはb以下 |
a≧b | a>=b (a=>b は誤り) | aはb以上 |
a≠b | a!=b (a=!b は誤り) | aはbと等しくない |
(a<b)or(c<a) | (a<b)||(c<a) | aはbより小さいか,またはaはcより大きい |
(b<a)and(a<c) | (b<a)&&(a<c) | aはbより大きく,かつaはcより小さい |
(a=b)and(c=d)and(e=f) | (a==b)&&(c==d)&&(e==f) | aとbが等しく,かつcとdが等しく,かつeとfが等しい |
(b<a)and(a≠c) | (b<a)&&(a!=c) または (b<a)&&(!(a==c)) |
aはbより大きく,かつaはcと等しくない |
ドモルガンの定理
ドモルガンの定理により同値な関係 | |
!((a<b)&&(c<d)) | (!(a<b))||(!(c<d)) |
!((a<b)||(c<d)) | (!(a<b))&&(!(c<d)) |
よくある条件式の誤り(その1)
表現 | |
数学の表現 | x<3,7<xの場合は..... |
誤ったC言語による表現 | if (x<3,7<x)
{ 文法上は誤りではないのでコンパイルエラーにはならない if (7<x) { と同じ意味になってしまう |
考え方 |
数学の表現をより論理的に書き直すと 「x<3または7<xの場合は.....」 となる |
正しいC言語による表現 | if ( x<3 || 7<x ) { |
よくある条件式の誤り(その2)
表現 | |
数学の表現 | 3≦x≦7の場合は..... |
誤ったC言語による表現 | if (3<=x<=7)
{ 文法上は誤りではないのでコンパイルエラーにはならない if ((3<=x)<=7) { の意味になってしまい,次の中級者向け説明に示す解釈になり, このif文は常に真になってしまう。 |
考え方 |
数学の表現をより論理的に書き直すと 「3≦xかつx≦7の場合は.....」 |
正しいC言語による表現 | if ( 3<=x && x<=7 ) { |
条件の真偽のC言語での取り扱い(中級者向け説明)
C言語では真偽を数値で表すことになっていて,偽は0,真は0以外の値ということになっている。
例えば,同様に,引数で与えた整数値が文字コードで大文字であるかどうか調べる関数int
isupper(int ch)は, また永久ループは |
B.4 sizeof算子 |
---|
sizeof演算子は,変数の型,変数,配列変数が何バイトで出来ているかを計算する演算子である。
例えば
sizeof(char)は1,sizeof(short
int)は2,sizeof(long int)は4を表す。
また
char ch;
short int
sx;
の時
sizeof(ch)は1,sizeof(sx)は2を表す。
char
mystring1[]="abcdefg";
char
mystring2[100]="ABCDEFG";
の時
sizeof(mystring1)は8を表す。(文字列終端も含まれる)
sizeof(mystring2)は100を表す。
short
int xx[]={123,456,789,234,567,890,987,654,321};
int
num;
の時
num=sizeof(xx)/sizeof(short
int);
で,numには要素数9が入る。
変わった例では定数の内部表現を見ることが出来る
printf("%d %d %d
%d\n",sizeof(123),sizeof(123.123),sizeof('A'),sizeof(1==1));
では,windowsでは「4 8
4 4」が得られた。整数扱いの数はintになり実数扱いの数はdoubleになるようだ
APPENDIX 1 BOOL演算 |
---|
C言語で用いられるブール演算は基本的に4つあり,演算対象とする値は0と1である。
(1)アンド演算(and)
演算
結果
0 and 0
0
0 and 1
0
1 and 0
0
1 and 1
1
「両方1の組み合わせのみ1で,その他の組み合わせは0」
演算
結果
x and 0
0
x and 1
x
(2)オア演算(or)
演算
結果
0 or 0
0
0 or 1
1
1 or 0
1
1 or 1
1
「両方0の組み合わせのみ0で,その他の組み合わせは1」
演算
結果
x or 0
x
x or 1
1
(3)ノット演算(not)
演算
結果
not 0
1
not 1
0
(4)イクスクルーシブオア演算(xor)(排他的論理和)
演算
結果
0 xor 0
0
0 xor 1
1
1 xor 0
1
1 xor 1
0
「お互いに値が異なる組み合わせで1,お互いに同じ値の組み合わせは0」
演算
結果
x xor 0
x
x xor 1
not x
APPENDIX 2 演算子の優先順位 |
---|
C言語の演算子には実行優先順位がある。算術演算において乗算除算が加算減算に優先することも,C言語の演算子の実行優先順位に含まれている。
順位 | 演算子 | 説明 |
1 |
[ ] ( ) . -> 後置 ++ 後置 -- | [ ] は配列,「. ->」は構造体メンバの区切り |
2 |
前置 ++ と前置 -- | |
3 |
sizeof & * + - ~ ! | すべて単項演算子 sizeof &(アドレスを表す) *(ポインタ) +(+3など) -(-5など) ~ ! |
4 |
キャスト | 例 double x; の場合 (int)x |
5 |
* / % | 2項演算子 乗算、除算、剰余 |
6 |
+ - | 2項演算子 加算、減算 |
7 |
<< >> | ビットごとのシフト |
8 |
< > <= >= | 関係演算子 |
9 |
== != | 関係演算子 |
10 |
& | ビットごとの AND |
11 |
^ | ビットごとの排他的 OR |
12 |
| | ビットごとの OR |
13 |
&& | 条件論理の AND |
14 |
|| | 条件論理の OR |
15 |
? : | 3項演算子 |
16 |
= *= /= %= += -= <<= >>= &= ^= |= |
単純代入と複合代入 |
17 |
, | 順次評価 |