PPT

情報処理Ⅱ
第6回:2003年11月25日(火)
レポート総評(1)

「メタ」を持つ様々な用語があった.


メタクラス; メタコンピュータ; メタサーチ(エンジン), メタ
検索(エンジン); メタデータ; メタディレクトリ; メタファイ
ル; メタプログラム; メタボール; メタミュージック; メタ情
報; メタ文字, メタキャラクタ; (UML)メタモデル; HTMLの
METAタグ; METAキー (Emacsで使用する)
「メタ」に関する興味深い記述が見られた.

メタというのは相対的な考えであり,自分がどこを視点と
して選ぶかによって推移するものです.
(http://www.ogis-ri.co.jp/otc/hiroba/technical/Squeak4/pdf/Squeak4.pdf)
レポート総評(2)

体裁として不適切なものがあった.








B5ルーズリーフでの提出
2枚を超えている
ノンブル(ページ番号)がない
左上をステープラで綴じていない
敬体(です体)で書いている
行間あけすぎ
用紙の裏に,レポートと関係ない図面らしきもの
Webページやコマンド解説文書を引き写しただけ
問題(授業がつまらない人のために)

整数値の2進表現を出力するプログラムを作成せよ.
整数値の型(int, char, longなど)も考慮せよ.


例: char型の40 ⇒ 00101000
次の3つの式の中で,同じ動作をするのはどれとどれ
か?



*p++ = *q++;
*(p++) = *(q++);
(*p)++ = (*q)++;
演算子(Operator)

これまで使用してきた演算子


+, -, =, +=, ++, *, &, [ ] など
学ぶこと


C言語ではどんな演算子が使用できるか?
演算子間の優先順位はどうなっているか?

例: 1 + 2 * 3 と書けば,(1 + 2) * 3 ではなく
1 + (2 * 3) と解釈される.このとき,* は + よりも
優先順位が高いという.
用語説明

演算対象をオペランド(operand)という.


y = x + 1; のとき,
x と1 は,演算子 + のオペランド
y と x + 1 は,演算子 = のオペランド
「left value」の略
代入できるオブジェクトを左辺値(lvalue)という.


*p = (++q) + 1;
としたときの *p と q は左辺値である.
&x や,int z[10]; としたときの z は左辺値ではない.
2項演算子





加減算演算子: +, 乗除演算子(1): *, /
乗除演算子(2): % (剰余を求める.オペランドは整数)
関係演算子: <, >, <=, >=, ==, !=
暗黙の型変換が起こる場合を除き,オペランドは同一の
型でなければならない.

char *x; int y; に対して,if (x <= y) はNG,if (*x <= y) はOK.
単項演算子





間接演算子: *
アドレス演算子: &
増分演算子,減分演算子: ++, -正負の符号: +, sizeof演算子: sizeof


sizeof(char) は1,char x; に対して sizeof(x) も1.
しかし sizeof('0') は sizeof(int) と同じ値になる.
キャスト演算子: (型名)

オペランドは変数名,式
もしくは型名.
慣習として ( ) をつけるが,
関数呼び出しではない.
( ) は必須
1/3は0.しかし,(double)1/3 は 0.333…となる.
さらに,(double)(1/3) は 0.0 となる.
単項演算子:注意点(1)


原則として,オペランドの前(左)につける.
右から左に結合する.


**p は,*(*p) である.つまり右側の演算子*を評価してから
左側を評価する.
参考: a * b * c は (a * b) * c である.つまり左側の演算子*
を評価してから右側を評価する.
単項演算子:注意点(2)

増分演算子と減分演算子はオペランドの後ろにつけるこ
ともできるが,前につけるのと意味が異なる.




x = ++y; ⇒ y = y + 1; x = y; と同じ(増分を先に評価)
x = y++; ⇒ x = y; y = y + 1; と同じ(増分を後で評価)
増分演算子と減分演算子のオペランドは,左辺値であり,
かつ算術型またはポインタ型でなければならない.
sizeof演算子のオペランドは式として評価されない.

sizeof(x++) としても x の値は増えない.
代入演算子

=, +=, -=, *=, /=, %=


左側のオペランドは左辺値でなければならない.


x + 1 = y; や (*p)++ = (*q)++; はNG.
右から左に結合する.


x 記号= y; は,x = x 記号 y; と同じ.
x += *y = z + 2; ⇒ *y = z + 2; x += *y; と同じ.
左辺値に格納される値を演算結果とする.暗黙の型変換
に注意.

double d; int x; に対して
x = d = 1./3.; とすると,d = 0.333…; そして x = 0;
d = x = 1./3.; とすると,x = 0; そして d = 0.0;
論理演算子





AND: && (2項演算子)
OR: || (2項演算子)
NOT: ! (単項演算子)
優先順位は ! > && > ||
真偽とC言語での表現





int a[10];
…
if (x >= 0 && x < 10 && a[x] == y)
とすると,x<0 や x≧10のときは
a[x] == y を評価しない.
真: 0以外に評価される値
偽: 0に評価される値
例: 1 && 2は真(具体的には,1)である.
&&の左を偽と評価すれば,右は評価しない.
||の左を真と評価すれば,右は評価しない.
論理演算
x


y
x && y
x || y
x
!x
真 真
1
1
真
0
偽 真
0
1
偽
1
真 偽
0
1
偽 偽
0
0
偽:整数型なら0,浮動小数点型なら0.0,ポインタ型な
らNULLと等しくなる値.
真:偽でないスカラ型(整数型,浮動小数点型もしくは
ポインタ型)の値.
ビット演算子

整数値をビット(0と1)の並びとみなし,ビット単位
(bitwise)で演算を行う.いずれも2項演算子.






ビット単位AND: &
ビット単位OR: |
ビット単位XOR: ^
例: 1 & 2は0である.
優先順位は & > ^ > |
代入演算子 &=, |=, ^= も利用可能.
ビット演算


x
y
x&y
x|y
x^y
1
1
1
1
0
0
1
0
1
1
1
0
0
1
1
0
0
0
0
0
ビット単位の演算結果であることに注意.
0 ^ 1 = 1, 1 ^ 1 = 0 (ビットの反転)
x ^ x = 0 (ビットのクリア)が成り立つ.
ビット演算子の利用例

一部のビットを0にする.


一部のビットを1にする.


char x = 0x23; のとき x | 0x0f は0x2f,x | 0xf0 は0xf3.
一部のビットを反転する.


char x = 35; のとき x & 0x0f は3,x & 0xf0 は32.
char x = 0x23; のとき x ^ 0x0f は0x2c,x ^ 0xf0 は0xd3.
変数 x の全部のビットを(手っ取り早く)反転する.

x ^= -1; とすればよい.
シフト演算子

整数値をビットの並びとみなす.



いずれも2項演算子で,左は整数値,右はシフトする
ビット数(0 以上の整数値).



左シフト: <<
右シフト: >>
5 << 3は40.
5
→ 00000101 ← 40 >> 3
5 << 3 → 00101000 ← 40
負の数を右シフトしたときの結果は処理系依存.
代入演算子 <<=, >>= も利用可能.
例題1

整数値の2進表現を出力するプログラム


1 && 2 と 1 & 2 を比較する.
これまでに書いた論理演算・ビット演算の例を検証する.
その他の演算子

関数呼び出し: ( )
配列の添字: [ ]
コンマ演算子: ,

例: for (i = 0, p = base; function(p[i], 1); i++)


これらは構文の一部であり,演算子ではない.
演算子の優先順位
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
関数呼び出し( ),配列の添字[ ]
単項演算子(!, 単項*, ++, 単項+, sizeof, キャストなど)
乗除(2項*, /, %)
加減算(2項+, 2項-)
シフト(<<, >>)
関係(<, >, <=, >=)
関係(==, !=)
ビット演算(&)
ビット演算(^)
ビット演算(|)
論理演算(&&)
論理演算(||)
3項演算子(?:)
代入演算子(=, +=など)
コンマ(,)
高い
低い
優先順位を変えたければ,( )で囲む.( )が何重にもなることがある.{ }や[ ]は,
この目的で使用できない.

まとめ




C言語では多彩な演算子が利用できる.いくつかは数学
の記号に近く,いくつかはC言語独特である.
各演算子には優先順位がある.
同じ優先順位の演算の評価順序を決めるのは,結合の方
向である(演算子により,「左から右」か「右から左」
かが決まっている).
評価されない式に注意.
発展的な話題:代入の順序について

冒頭の問題に対する解答


*p++ = *q++; と *(p++) = *(q++); と
*p = *q; p++; q++; は同じ.
オペランドの評価順序は,特に明記したものを除いて,
不定(処理系依存)である.式の中で同一のオブジェク
トに2つ以上の代入をしないよう心がける.

function(++c, ++c); は
function(c + 1, c + 2); ++c; ++c; かもしれないし,
function(c + 2, c + 1); ++c; ++c; かもしれない.
発展的な話題:3項演算子

オペランド1 ? オペランド2 : オペランド3



まずオペランド1を評価する.それが真であればオペラン
ド2を,偽であればオペランド3を評価して,その値を演算
結果とする.
例: t = (a > b) ? a : b; ⇒ if (a > b) t = a; else t = b;
a > b ? a : b = 10; はNG(コンパイルエラー).
しかし *(a > b ? a : b) = 10; はOK.