Transcript 運算子

最新
C
程式語言
蔡明志 編著
4
 4.1
 4.2
 4.3
 4.4
 4.5
 4.6
 4.7
 4.8
 4.9
 4.10
運算子
指定運算子
四則運算子
sizeof運算子
餘數運算子
遞增與遞減運算子
優先順序
位元運算子
位元運算子的用途
運算式的值
型態轉換
2
4.1
指定運算子
 等號(=)常被誤認為“等於”的意思,但在C語
言裡它卻是一種執行數值設定的運算子,譬如
說:
value = 100;
 便會把100設定給變數value,符號'='謂之為"
指定運算子"(assignment operator);它是一
個二元運算子,也就是說,該運算子將接受兩
個運算元,其中的左運算元必須是個變數,嚴
格說起來應該是資料儲存空間,ANSI C採用了
lvalue (left value)這個術語來指稱此類運算
元,譬如變數名稱便為合法的lvalue,而常數
則非。指定運算子右方的運算元則可以為常數、
3
 下面的例子:
100 = value;
這種運算式完全沒有意義,在編譯過程間
便會被偵測出來。
num = num + 1;
=> num + 1
14
num = 15; => 15
num
num
4
4.2
四則運算子
表4-1 算術運算子
運算子
運作
+
加法
-
減法
*
乘法
/
除法
5
/* ch4 op4s.c */
#include <stdio.h>
#include <stdlib.h>
#define PI 3.14
int main()
{
int r1, r2;
double area1, area2;
double total, diff;
printf("Calculating areas of circles ...\n\n");
printf(" Input radius of first circle : ");
scanf("%d", &r1);
area1 = PI * r1 * r1;
/* math formula */
printf("\n ===> The area of first circle is %.2f\n\n",area1);
printf(" Input radius of second circle : ");
scanf("%d", &r2);
area2 = PI * r2 * r2;
/* math formula */
printf("\n ===> The area of second circle is %.2f\n\n", area2);
total = area1 + area2;
diff = area1 - area2;
printf("Total area is %.2f\n", total);
printf("Difference is %.2f\n", diff);
system("PAUSE");
return 0;
}
6
 程式op4s.c的執行結果如下:
Calculating areas of circles ...
Input radius of first circle : 12
===> The area of first circle is 452.16
Input radius of second circle : 8
===> The area of second circle is 200.96
Total area is 653.12
Difference is 251.20
7
/* ch4 divide.c */
#include<stdio.h>
#include <stdlib.h>
int main()
{
int op1 = 10;
int op2 = 4;
double op3 = 10.0;
double op4 = 4.0;
printf("Divide and Trunc ...\n\n");
printf(" %d / %d = %d\n",op1,op2,op1/op2);
printf(" %d / %.2f = %.2f\n",op1,op4,op1/op4);
printf(" %.2f / %.2f = %.2f\n",op3,op4,op3/op4);
printf(" %.2f / %d = %.2f\n",op3,op2,op3/op2);
system("PAUSE");
return 0;
}
8
 結果是這樣的:
Divide and Trunc ...
10 / 4 = 2
10 / 4.00 = 2.50
10.00 / 4.00 = 2.50
10.00 / 4 = 2.50
9
4.3 sizeof運算子
 運算元出現的形式有兩種:若運算元本身
即為型態名稱(例如int、float...等
等),則一定要括於小括號內;至於若是
變數名稱是資料物件,那麼小括號的有無
都沒有關係。
10
/* ch4 sizeof.c */
#include <stdio.h>
#include <stdlib.h>
int main()
{
short short_num = 0;
int int_num = 0;
long long_num = 0;
printf("Operator sizeof in Byte(s)...\n\n");
printf("
printf("
printf("
printf("
printf("
printf("
printf("
Type <char> : %d Byte(s).\n", sizeof (char));
Type <short> : %d Byte(s).\n", sizeof (short));
Type <int> : %d Byte(s).\n", sizeof (int));
Type <long> : %d Byte(s).\n", sizeof (long));
Type <float> : %d Byte(s).\n", sizeof (float));
Type <double> : %d Byte(s).\n", sizeof (double));
Type <long double>:%d Byte(s).\n", sizeof(long double));
printf("\n");
printf(" Variable short_num:%d Byte(s).\n", sizeof short_num);
printf(" Variable int_num : %d Byte(s).\n", sizeof int_num);
printf(" Variable do_fl : %d Byte(s).\n", sizeof(long_num));
system("PAUSE");
return 0;
}
11
 執行的結果是這樣的:
Operator sizeof in Byte(s)...
Type <char> : 1 Byte(s).
Type <short> : 2 Byte(s).
Type <int> : 4 Byte(s).
Type <long> : 4 Byte(s).
Type <float> : 4 Byte(s).
Type <double> : 8 Byte(s).
Type <long double> : 8 Byte(s).
Variable short_num : 2 Byte(s).
Variable int_num : 4 Byte(s).
Variable do_fl : 4 Byte(s).
12
 由本範例即可清楚地看到各種型態的實際
大小,其中int與long int型態是一樣的。其
實sizeof運算子所產生的值應該是unsigned
int型態,不過在此以%d規格處理也沒有
錯誤。以上是在Visual C++ 編譯程式所產
生的結果,若使用不同的編譯程式,結果
也許會有所不同。
13
4.4
餘數運算子
 餘數運算子(modular operator)的表示記
號為'%',同樣是二元運算子:
a % b
 該運算子可取得a除以b後所留下的餘數,
特別注意到本運算子僅能作用於整數型
態;換句話說,a和b這兩個運算元都必須
是整數資料。
14
/* ch4 mod.c */
#include <stdio.h>
#include <stdlib.h>
int main()
{
unsigned int sec, min, hour;
printf("Time conversion...\n\n");
printf("How many seconds :\n
scanf("%d", &sec);
min = sec / 60;
sec = sec % 60;
===> ");
hour = min / 60;
min = min % 60;
printf("\n %d hours, %d minutes, and %d
seconds.\n",hour,min,sec);
system("PAUSE");
return 0;
}
15
 分別處理時數和分鐘,其原理是相同的。
Time conversion...
How many seconds :
===> 12345
3 hours, 25 minutes, and 45 seconds.
16
4.5 遞增與遞減運算子
 遞增(減)運算子應可說是C程式風格的一項特色,
它使得程式碼更為簡潔。
++ 遞增(increment)運算子
-- 遞減(increment)運算子
 遞增運算子僅完成一件單純的工作,亦即把某
變數值加1:
num++;
便相當於
num = num+1;
17
 遞增運算子可依運算子的位置不同而有兩種形
式:第一種是++出現於運算元前面,即所謂的
“前置”(prefix)模式,另一種則為++位於運算
元之後,即“後繼”(postfix)模式。
++num;
num++;
前置模式
後繼模式
18
 就這兩條敘述而言,最後得結果都會使
num的值增加了1,不過它們的工作原理卻
不相同,不同之處在於遞增運算發生的時
機。當該運算子出現於運算式中時,後繼
形式的num++會先以原始的num數值作用
於整個運算式,然後才把num加1;至於前
置形式的++num則是先增加num的值,接
著才以作用後的數值帶入整個運算式。
19
/* ch4 crement */
#include <stdio.h>
#include <stdlib.h>
int main()
{
int x,y;
int result;
x = 3;
y = 5;
result = x * (y++);
printf("result = %d x = %d y = %d\n",result,x,y);
result = x * (++y);
printf("result = %d x = %d y = %d\n",result,x,y);
system("PAUSE");
return 0;
}
20
 因此result的值等於3*5,即15,然後再執行
y++,所以y的值變成6,x值仍舊不變:
result = 15 x = 3 y = 6
result = 21 x = 3 y = 7
 接著執行到另一個運算:
result = x * (++y);
 記住,此時的x等於3,y等於6。由於該運算為
前置形式,所以效果等同於
++y;
/* y等於7 */
result = x*y;
21
4.6
優先順序
表4-2 運算子的運算優先順序與結合性
運算子
結合性
( )
由左到右
(單元) +(正)、-(負)
由左到右
*/
由左到右
(二元) +(加)、-(減)
由左到右
=
由右到左
22
 看看優先順序的影響:
/* ch4 priority.c */
#include <stdio.h>
#include <stdlib.h>
int main()
{
int x, y, z;
int res1, res2;
x = 2;
y = 5;
z = 10;
res1 = x + y * x - z / x;
res2 = (x + y) * (x - (z / x));
printf("res1 = %d\n",res1);
printf("res2 = %d\n",res2);
system("PAUSE");
return 0;
}
23
位元運算子
4.7
 C語言共擁有四種位元運算子(bitwise operator):
~(NOT), &(AND),|(OR),以及^(XOR),它們均運
作於整數型態的資料上。另外還有兩個位移運算子
(shift operator):<<(左移)與>>(右移),它們能
將位元內容分別向左或向右遞移指定的次數。
7
6
5
4
3
2
1
0
 當我們說位元0時即代表最右邊的低次位元(loworder bit),而位元7則為最左方的高次位元(highorder bit)。
24
 位元 NOT 運算子: ~
 運算子 ~ 僅需一個運算元,它會將運算元的每
個位元做0與1的互換:
NOT
0
1
1
0
25
 舉例來說,變數value的型態為unsigned
char,內含值是20,二進位表示法將寫
成:
unsigned char
0
0
0
1
0
1
0
0
~value
26
 如果以~運算子作用於value之上,就會變
成底下的位元樣式(bit pattern):
unsigned char
1
1
1
0
1
0
1
1
~value
27
 位元 AND 運算子: &
 運算子 & 是個二元運算子,對於左右兩個
運算元而言,唯有在相對應的位元均為1
的情形下,結果值的位元才會是1。往後
我們都以真值表(True Table)來表示位元運
算子的作用:
0
0
0
0
1
0
1
0
0
1
1
1
AND(&)
28
 舉個例子來說:
&)
0
1
1
0
0
1
0
0
1
1
0
1
1
0
1
0
0
1
0
0
0
0
0
0
 兩個運算元中唯有位元6的兩個位元都是1,
所有結果值的位元樣式裡,僅有該位元是
1,其餘位元則均為0。
29
 位元 OR 運算子: |
 運算子 | 也是個二元運算子,它和 & 一
樣,也會逐一比較兩個運算元的相對應位
元,但只要其中有一個位元是1時,結果
的相對應位元便為1:
0
0
0
0
1
1
1
0
1
1
1
1
OR( | )
30
 再拿前面的例子做一比較:
|)
0
1
1
0
0
1
0
0
1
1
0
1
1
0
1
0
1
1
1
1
1
1
1
0
 除了最右方(即位元0)的位元為0之外,其
餘的位元配對中,都至少出現一個1,所
以最後的結果只有位元0的位置出現0,其
餘都是1。
31
 位元 XOR 運算子: ˆ
 運算子 ˆ 和OR運算子頗為類似,但是在
逐一比對各個位元時,若是兩個位元值相
同時,結果的位元方為0,否則便是1。
0
0
0
0
1
1
1
0
1
1
1
0
XOR( ^ )
32
 和OR的差別在於1與1的情況下,得到的
結果卻是0,因為兩個位元值相同。看看
底下的例子:
^)
0
1
1
0
0
1
0
0
1
1
0
1
1
0
1
0
1
0
1
1
1
1
1
0
33
 左位移運算子: <<
 運算子<<會將左側運算元的位元樣式向左
遞移右側運算元指定的次數;右方空出來
的位元則以0填補,而移出的位元則會遺
失。
value = 20
0
00
0
0
1
0
0
1
1
0
0
拾棄
Value << 2 => 80
1
0
0
0
0
value << 2 (左移2位
元)
0
填入0
34
 右位移運算子: >>
 運算子>>會把左側運算元的位元樣式向右移動右側
運算元指定的次數;右方移出的位元將遺失,而左
方空出的位元則視資料型態而定。對於unsigned資
料來說,左側將以0填入,至於有號(signed)型態,
則多半填進符號位元(sign bit,即最左邊的位元)
的拷貝值,以便保證維持原始數值的正負符號。
(unsigned)value
1 0
0 0 1 1 1 0
value>>2(右移2位元)
0 0 1 0 0
填入0
0 1 1 10
拾棄
35
 假若是有號型態:
(signed)value
1 0
0 0 1 1 1 0
value>>2
1
sign bit
1
1 1 0 0
填入
sign bit 的值
0 1 1 10
拾棄
36
4.8 位元運算子的用途
 位元遮罩
 位元AND運算子常常做為遮罩(mask)使用,
之所以稱為遮罩,原因在於它可以將特定
幾個位元遮蓋起來(使之成為0),而使其
它位元原封不動顯現出來。
 我們只要把欲顯現的位元以 & 運算子與1
作用,而讓其它位元位置和0運算,就能
達到遮閉的效應。
37
 舉個例子來說,我們想把變數value的奇數
位元都遮蓋起來,而僅顯現偶數位元;首
先要建立一個遮罩常數,假設該常數稱為
MASK,其值設定為
MASK
1
偶
0
1
數
0
1
位
0
1
0
元
38
 然後將MASK與value透過 & 運算子來作
用
value
&) MASK
0
1
0
0
1
1
1
0
1
0
1
0
1
0
1
0
0
0
0
0
1
0
1
0
39
 打開特定位元
value
| ) MASK
0
1
0
0
1
1
1
0
1
0
1
0
1
0
1
0
1
1
1
0
1
1
1
0
 我們可以看到,偶數位元都設定成1,而
奇數位元仍保持原狀;理由也很簡單,在
位元OR邏輯運算下,1與任何值作用一定
會得到1,而0與其它值作用則維持不變
(0|0 == 0,0|1 == 1)。
40
 關閉特定位元
 想把變數value的偶數位元關閉:
value
& ) MASK
0
1
0
0
1
1
1
0
0
1
0
1
0
1
0
1
0
1
0
0
0
1
0
0
 可以看到偶數位元都被關閉了(即清除為0),
而奇數位元則維持不變。
41
 位元反相
 假定想把變數value的偶數位元反相,其它位元
維持原狀,那麼只要使遮罩常數的偶數位元為
1,奇數位元為0,再透過^ 運算子與value作用就
行了:
value
^ ) MASK
0
1
0
0
1
1
1
0
1
0
1
0
1
0
1
0
1
1
1
0
0
1
0
0
 可以看到偶數位元已做01互換;因為1^1 == 0,
而1^0 == 1;至於奇數位元則維持不變,理由在
於0^1 == 1,且0^0 == 0。
42
4.9
運算式的值
運算式
值
14
14
14+5060
5074
Sizeof (int)
4
43
/* ch4 op_value.c */
#include <stdio.h>
#include <stdlib.h>
int main()
{
int x, y, z;
int i, j;
x = y = z = -14;
printf("x = %d y = %d z = %d\n", x, y, z);
j = 3 * (i = 8 + 2);
printf("\ni = %d j = %d\n", i, j);
system("PAUSE");
return 0;
}
44
 重複同樣的過程,與分別取得。看看輸出
結果便可知曉:
x = -14 y = -14 z = -14
i = 10 j = 30
45