情報処理II

情報処理Ⅱ
第4回
2007年10月29日(月)
本日学ぶこと

演算子(Operator)




+, -, =, %, ++ ,&& ,||, == など
C言語ではどんな演算子が使用できるか?
演算子間の優先順位はどうなっているか?
• 例: 1 + 2 * 3 と書けば,(1 + 2) * 3 ではなく
1 + (2 * 3) と解釈される.このとき,* は + よりも
優先順位が高いという.
問題

整数が与えられたとき,そのビットパターンを出力できる?
• 例: (char型の) 40 のビットパターンは,00101000
• int型やlong型,float型のビットパターンは?
2
演算子一覧
1. 関数呼び出し( ),配列の添字[ ],構造体のメンバ参照(., ->)
2. 単項演算子(!, 単項*, ++, 単項+, sizeof, キャストなど)
3. 乗除(2項*, /, %)
4. 加減算(2項+, 2項-)
5. シフト(<<, >>)
6. 関係(<, >, <=, >=)
7. 関係(==, !=)
8. ビット演算(&)
9. ビット演算(^)
10. ビット演算(|)
11. 論理演算(&&)
12. 論理演算(||)
13. 3項演算子(? :)
14. 代入演算子(=, +=など)
15. コンマ(,)
入p.314
リpp.155-156

高い
優
先
順
位
低い
優先順位を変えたければ,( ) で囲む.( ) が何重にもなること
がある.{ } や [ ] は,この目的で使用できない.
3
単項演算子



増分演算子,減分演算子: ++, -正負の符号: +, sizeof演算子: sizeof



キャスト演算子: (型名)



リp.158
sizeof(char) は 1
char x; に対して sizeof(x) も 1
実数型やポインタ型の変
数もオペランドにできる.
オペランドは変数名,式
もしくは型名.
慣習として ( ) をつけるが,
関数呼び出しではない.
( ) は必須
1/3 は 0
(float)1/3 は 0.333…
(float)(1/3) は 0.0
4
単項演算子:注意点


原則として,オペランドの前(左)につける.
増分演算子と減分演算子はオペランドの後ろにつけることも
できるが,前につけるのと意味が異なる.



x = --y; ⇒ 「y = y - 1; x = y;」 と同じ(減分を先
に評価).
x = y--; ⇒ 「x = y; y = y - 1;」 と同じ(減分を後
で評価).(x = y)--; ではない.
増分演算子と減分演算子のオペランドは,左辺値であり,か
つ算術型またはポインタ型でなければならない.
入pp.209-210
リp.158
5
ビット演算子

整数値をビット(0と1)の並びとみなし,ビット単位
(bitwise)で演算を行う.







ビット単位AND: & (2項演算子)
ビット単位OR: | (2項演算子)
ビット単位XOR: ^ (2項演算子)
ビット単位NOT: ~ (単項演算子)
例: 1 & 2 は0である.
優先順位は ~ > & > ^ > |
代入演算子 &=, |=, ^= も利用可能.
入p.203-204
リp.161
6
ビット演算


x
y
x&y
x|y
x^y
x
~x
1
1
1
1
0
1
0
0
1
0
1
1
0
1
1
0
0
1
1
0
0
0
0
0
ビット単位の演算結果であることに注意.
0 ^ 1 = 1 ^ 0 = 1 (相補律)
1 ^ 1 = 0 (ビットの反転),
x ^ x = 0 (ビットのクリア)が成り立つ.
7
ビット演算子の利用例

一部のビットを0にする.


一部のビットを1にする.


入p.205
x & 0x0f : 00000011
x | 0x0f : 00101111
x ^ 0x0f : 00101100
char x = 0x23; のとき x ^ 0x0f は
0x2c,x ^ 0xf0 は0xd3.
全部のビットを反転する.

0x0f : 00001111
char x = 0x23; のとき x | 0x0f は
0x2f,x | 0xf0 は0xf3.
一部のビットを反転する.


char x = 35; のとき x & 0x0f は
3,x & 0xf0 は32.
x=35 : 00100011
~x : 11011100
x = ~x; とすればよい.
8
シフト演算子

整数値をビットの並びとみなす.



いずれも2項演算子で,左オペランドは整数値,右オペランド
はシフトするビット数(0以上の整数値).





左シフト: <<
右シフト: >>
5 << 3 は 40
m << n は m×2n
m >> n は m×2-n
5
→ 00000101 ← 40 >> 3
5 << 3 → 00101000 ← 40
負の数を右シフトしたときの結果は処理系依存.
代入演算子 <<=, >>= も利用可能.
入pp.205-206, p.123
リp.159
9
ビットパターン出力プログラム:準備

対象(入力)は,unsigned char型の値


簡単のため
ビット長が分かれば,他の整数型にも適用可能
x=40 …
char40.c
0
0
1
0
1
0
0
0
10
ビットパターン出力プログラム

検査方法
bの初期値は,1 << 7
 bの「増分」は,b >>= 1
 xの値は変化しない

x: 0
0
1
0
1
0
0
0
b: 1
0
0
0
0
0
0
0
x & bは0
⇒ 0 を出力
b: 0
1
0
0
0
0
0
0
x & bは0
⇒ 0 を出力
b: 0
0
1
0
0
0
0
0
x & bは非0
⇒ 1 を出力
0
0
1
x & bは0
⇒ 0 を出力
…
b: 0
0
0
0
0
11
3項演算子

オペランド1 ? オペランド2 : オペランド3



例: t = (a > b) ? a : b;
⇒ if (a > b) {t = a;} else {t = b;} と同じ
演算結果は左辺値ではない



まずオペランド1を評価する.それが真であればオペランド2を,
偽であればオペランド3を評価して,その値を演算結果とする.
× a > b ? a : b = 10;
○ *(a > b ? a : b) = 10;
a, bはポインタ変数
3項演算子の入れ子も可能だが,読みにくい
入p.216
リpp.162-163
12
その他の演算子



関数呼び出し: ( )
配列の添字: [ ]
コンマ演算子: ,

for (i=0, max=-1; scanf("%d", &d[i]) == 1;
i++)
これらは構文の一部であり,演算子ではない.
リp.157, p.165
13
補足



Cらしい式の例
結合規則
代入の順序
14
Cらしい式の例

xの値を1だけ増やす


xの値を倍にする



実数なら,x *= 2;
正の整数なら, x <<= 1;
xが偶数か奇数か判定する



x++;
if (x & 1)
初回授業で紹介した「if (x % 2)」は,やや非効率
xが0か否か判定する


if (!x)
ただし,if (x == 0) を推奨する
15
結合規則


同じ優先順位の演算子が並ぶ場合にも,評価の順序があり,
「結合規則」または「結合の向き」と呼ばれる.
左から右への結合(左結合)



x = y - z + 2; ⇒ x = (y - z) + 2; と同じ
右結合でない演算子
右から左への結合(右結合)


x += y = z + 2; ⇒ x += (y = z + 2); と同じ
単項演算子,3項演算子,代入演算子
入p.314
リp.148
16
代入の順序

オペランドの評価順序は,特に明記したものを除いて,不定
(処理系依存)である.式の中で同一の変数などに2つ以上
の代入をしないよう心がける.



リp.177
例: x=2; printf("%d %d", ++x, ++x); の出力は
「3 4」かもしれないし,「4 3」かもしれない.
例: x % 2 ? (x = x * 3 + 1) : (x /= 2); は意
図通りに動作する(が,if文で書くほうが自然).
「副作用完了点」という概念もあるが,授業では説明しない.
17
まとめ



Cでは多彩な演算子が利用できる.いくつかは数学の記号に
近く,いくつかはC独特である.
演算子ごとに「優先順位」と「結合規則」が決まっている.
真偽の扱い,評価されない式にも注意する.
18
値の評価の注意点




オーバーフロー
アンダーフロー
計算誤差
暗黙の型変換
19
範囲を越えるとどうなるか?

signed char型変数に13*13を格納すると?




13はint型定数で,13*13は,int型の169と評価される.
これをsigned char型変数に格納しようとすると,169から
256を引いた-87が代入される.
signed char a = 127; a++; だと,aの値は128では
なく-128になる.
値が,型の取り得る範囲を超えるために,変わってしまうこと
を,オーバーフロー(桁あふれ)という.
入p.134
リp.151
13x13.c
20
無限小?

1から始めて2でどんどん割っていくと,いずれは0になる.
double d;
for (d = 1; d > 0; d /= 2) {
printf("%g\n", d);
}

浮動小数点数の計算で,表現できる精度よりも小さくなり,値
が変わる(0などになる)ことを,アンダーフローという.
21
1なのに,1でない?

for文を用いて,0, 0.1, 0.2, ..., 1.0 を取り出す,
間違った方法
double d;
for (d = 0; d != 1; d += 0.1)


0.1という値を,計算機内で誤差なく表現できない.「計算誤
差」により,0.1×10が1でないという事態が起こる.
プログラミングの心がけ


(最善) 実数型はループ用変数にしない.
(次善) != ではなく,> や < を用いて判定をする.
入pp.136-137
リp.66
from0to1bad.c
22
異なる型の値同士の計算


1/3 と 1.0/3 と 1/3.0 と 1.0/3.0 は同じ値?
算術演算において,大きい範囲の型に揃えられる.




int > short, int > char (汎整数拡張)
long double > double > float >
long long > long > int (暗黙の型変換)
unsigned > signed
プログラミングの心がけ


unsignedとsignedの整数値を混在させて演算しない.
1/3 は,0.それ以外の上の式はすべて0.333…
リpp.150-153
23
代入時の型変換

代入演算子では,必ず左辺の型に変換される.

double d; int x; に対して
x = d = 1.0/3.0; ⇒ d = 0.333…; x = 0; と同じ
d = x = 1.0/3.0; ⇒ x = 0; d = 0.0; と同じ
24
まとめ

オーバーフロー,計算誤差,型変換に注意.
25