一、算術(shù)運算符
算術(shù)運算符分為單目和雙目操作:
- 單目操作是指對一個操作數(shù)進行操作。例如: -a是對a進行一目負操作岸晦。
- 雙目操作(或多目操作)是指兩個操作數(shù)(或多個操作數(shù))進行操作怔檩。
1.雙目運算符
- : 加法運算
- : 減法運算
- : 乘法運算
/ : 除法運算
% : 求余運算(又叫模運算)
重點說一下后兩個運算符:
- 除法運算符左右兩邊的數(shù)據(jù)類型決定了運算結(jié)果的類型博个。兩邊都是整數(shù)結(jié)果為整數(shù)讹蘑,有任一方是小數(shù)喜鼓,結(jié)果為小數(shù)。如果兩個整數(shù)相除有余數(shù)衔肢,舍棄余數(shù)。運算符右邊的數(shù)不能為0
- 整除運算符左右兩邊的數(shù)據(jù)必須都是整數(shù)豁翎,結(jié)果是這兩個數(shù)相除的余數(shù)值角骤。如果能整除,結(jié)果為0
int a = 3;
int b = 2;
int sum, diff, product, res, mod;
// +
sum = a + b;
printf("sum = %d\n", sum);//5
// -
diff = a - b;
printf("diff = %d\n", diff);//1
// *
product = a * b;
printf("product = %d\n", product);//6
// /
res = a / b;
printf("res = %d\n", res);//1
// %
mod = a % b;
printf("mod = %d\n", mod);//1
接下來我們來看它的本質(zhì)心剥,在相應(yīng)的ide應(yīng)該有對象的匯編代碼
(去掉打印后的)
idivl 除數(shù)存儲在ax寄存器 余數(shù)在dx寄存器
Cpluse`main:
0x100000f50 <+0>: pushq %rbp
0x100000f51 <+1>: movq %rsp, %rbp
0x100000f54 <+4>: xorl %eax, %eax
0x100000f56 <+6>: movl $0x0, -0x4(%rbp)
0x100000f5d <+13>: movl %edi, -0x8(%rbp)
0x100000f60 <+16>: movq %rsi, -0x10(%rbp)
0x100000f64 <+20>: movl $0x3, -0x14(%rbp) //局部變量a
0x100000f6b <+27>: movl $0x2, -0x18(%rbp) //局部變量b
0x100000f72 <+34>: movl -0x14(%rbp), %ecx
0x100000f75 <+37>: addl -0x18(%rbp), %ecx // a+b的值放到寄存器ecx
0x100000f78 <+40>: movl %ecx, -0x1c(%rbp) //寄存器ecx 的值放到局部變量sum中存儲
0x100000f7b <+43>: movl -0x14(%rbp), %ecx
0x100000f7e <+46>: subl -0x18(%rbp), %ecx //a-b的值放到寄存器cx前4個字節(jié)
0x100000f81 <+49>: movl %ecx, -0x20(%rbp) //寄存器ecx 的值放到局部變量diff中存儲
0x100000f84 <+52>: movl -0x14(%rbp), %ecx
0x100000f87 <+55>: imull -0x18(%rbp), %ecx //a*b的值放到寄存器ecx前4個字節(jié)
0x100000f8b <+59>: movl %ecx, -0x24(%rbp) //寄存器ecx 的值放到局部變量product中存儲
0x100000f8e <+62>: movl -0x14(%rbp), %ecx
0x100000f91 <+65>: movl %eax, -0x30(%rbp)
0x100000f94 <+68>: movl %ecx, %eax
0x100000f96 <+70>: cltd
0x100000f97 <+71>: idivl -0x18(%rbp) //a/b的值放到寄存器eax前4個字節(jié)
0x100000f9a <+74>: movl %eax, -0x28(%rbp) //寄存器ecx 的值放到局部變量res中存儲
-> 0x100000f9d <+77>: movl -0x14(%rbp), %eax
0x100000fa0 <+80>: cltd
0x100000fa1 <+81>: idivl -0x18(%rbp) //a%b的余數(shù)放到寄存器edx前4個字節(jié)
0x100000fa4 <+84>: movl %edx, -0x2c(%rbp) //寄存器ecx 的值放到局部變量mod中存儲
0x100000fa7 <+87>: movl -0x30(%rbp), %ecx
0x100000faa <+90>: movl %ecx, %eax
0x100000fac <+92>: popq %rbp
0x100000fad <+93>: retq
2.單目運算符
- ++ 操作數(shù)加1
- -- 操作數(shù)減1
這幾句最終達到的效果相同,在混編中執(zhí)行的邏輯也完全相同
x = x + 1;
x++;
++x;
但是進行賦值操作就會導致差異
x = m++; // 表示將m的值賦給x后, m加1邦尊。
x = ++m; // 表示m先加1后, 再將新值賦給x。
二优烧、賦值語句中的數(shù)據(jù)類型轉(zhuǎn)換
1. 賦值運算符
int a = 0;
a = a + 5;
a += 5;
a = a - 3;
a -= 3;
第二行和第三行意思相同蝉揍,第四行和第五行意思相同,可以互相替換畦娄。這是一種C語言中的簡便寫法又沾。
2. 類型轉(zhuǎn)換
類型轉(zhuǎn)換是指不同類型的變量混用時的類型改變弊仪。
2.1 隱式類型轉(zhuǎn)換
基本原則:
- 在賦值語句中, 等號右邊的值轉(zhuǎn)換為等號左邊變量所屬的類型
- 不同類型混合計算時,結(jié)果類型為數(shù)據(jù)類型級別較高的
- 所有的浮點預算都是以double進行的
數(shù)據(jù)類型級別順序:
char, short < int < float < double
int a, b = 3;
float f = 1.5;
a = f * b; // 整數(shù)和浮點類型運算杖刷,結(jié)果為浮點類型励饵,因為它類型級別高
printf("a = %d\n", a);
a = f; // 把一個浮點類型的變量賦值給整數(shù)類型,小數(shù)部分會被自動舍去
printf("a = %d\n", a);
這里有個重點問題需要強調(diào)滑燃,浮點類型的和整數(shù)類型計算時役听,結(jié)果為浮點類型。我們看一個常見問題表窘。
float f;
int a = 5;
f = a / 2;
printf("f = %f\n", f);
這段程序的運行結(jié)果是:
f = 2.0000
原因在于典予,a是個整數(shù),2也是個整數(shù)乐严,它們的計算結(jié)果也是整數(shù)瘤袖。此時,就已經(jīng)舍棄了計算結(jié)果中的小數(shù)部分麦备。因此孽椰,賦值時就自然沒有小數(shù)部分。
如果我們需要得到f = 2.5怎么辦呢凛篙?可以這樣寫:
float f;
int a = 5;
f = a / 2.0;
printf("f = %f\n", f);
因為整數(shù)a和浮點數(shù)2.0計算的結(jié)果是浮點型(double)黍匾,因此保留了小數(shù)部分。之后再把=右邊的double類型轉(zhuǎn)換成左邊的float類型呛梆。仔細想想锐涯,能理解吧。
2.2 強制類型轉(zhuǎn)換
在計算中填物,我們常常需要主動要求計算機改變變量的類型纹腌。這是可以這樣做。
(數(shù)據(jù)類型)(表達式或變量)
按照這種格式寫滞磺,右邊部分的類型就會被強制轉(zhuǎn)換成左邊括號中的類型升薯。看看具體代碼:
float f;
f = 6.6 / 3;
printf("f = %f\n", f);
f = (int)6.6 / 3;
printf("f = %f\n", f);
f = (int)(6.6 / 3);
printf("f = %f\n", f);
三击困、關(guān)系運算符
1.關(guān)系運算符
關(guān)系運算符的作用是比較符號兩邊的元素
> 大于
>= 大于等于
< 小于
<= 小于等于
== 等于
!= 不等于
關(guān)系運算符都是雙目運算符涎劈,其結(jié)合性均為左結(jié)合。關(guān)系運算符的優(yōu)先級低于算術(shù)運算符阅茶,高于賦值運算符蛛枚。也就是說,在一個沒有括號的關(guān)系運算表達式中脸哀,<蹦浦、<=、>撞蜂、>=要先于==和!=發(fā)揮作用盲镶。相同級別的預算符從左向右計算侥袜。
2.關(guān)系表達式
關(guān)系表達式的一般形式為:
例:
a + b > c - d
x > 3 / 2
‘a(chǎn)’ + 1 < c
-i - 5 * j == k + 1
也允許出現(xiàn)嵌套的情況。例:
a > (b > c)
a != (c == d)
關(guān)系表達式的值是“真”和“假”徒河,用“1”和“0”表示系馆。如:
5 > 0的值為“真”,即為1顽照;
(a = 3) > (b = 5)由于不成立由蘑,故其值為假,即為0代兵。
例:
char c = 'k';
int i = 1, j = 2, k = 3;
float x = 3e + 5, y = 0.85;
printf("%d, %d\n", 'a' + 5 < c, -i - 2 * j >= k + 1);
printf("%d, %d\n", 1 < j < 5, x - 5.25 <= x + y);
printf("%d, %d\n", i + j + k == -2 * j, k == j == i + 5);
- 字符變量以它對應(yīng)的ASCII碼參與運算
- 對于含多個關(guān)系運算符的表達式尼酿,如k == j == i + 5,根據(jù)運算符的左結(jié)合性植影,先計算k == j裳擎,該式不成立,其值為0思币,再計算0 == i + 5鹿响,也不成立,故表達式值為0谷饿。
表達式為真惶我,值為1。表達式為假博投,值為0
需要注意的是绸贡,C語言中經(jīng)常用0代表假,非零代表真毅哗。
四听怕、邏輯運算符
邏輯運算符相當于數(shù)學中的(且、或虑绵、非)尿瞭,我們叫做“邏輯與”、“邏輯或”和“邏輯非”翅睛。
&& 邏輯與
|| 邏輯或
! 邏輯非
前兩個是雙目運算符筷厘,最后一個是單目預算符。
邏輯與:兩邊都為真時返回真宏所,否則返回假;
邏輯或:只要任意一個為真就返回真摊溶,否則返回假爬骤;
邏輯非:符號右邊是真,則返回假莫换;符號右邊是假霞玄,則返回真骤铃。
三、按位運算符
C語言和其它高級語言不同的是它完全支持按位運算符坷剧。這與匯編語言的位操作有些相似惰爬。
按位運算符有:
& 位邏輯與 // 參加運算的兩個數(shù),換算為二進制(0惫企、1)后撕瞧,進行與運算。只有當相應(yīng)位上的數(shù)都是1時狞尔,該位才取1丛版,否則該為為0。
| 位邏輯或 //參加運算的兩個數(shù)偏序,換算為二進制(0页畦、1)后,進行或運算研儒。只要相應(yīng)位上存在1豫缨,那么該位就取1,均不為1端朵,即為0好芭。
^ 位邏輯異或 //參加運算的兩個數(shù),換算為二進制(0逸月、1)后栓撞,進行異或運算。只有當相應(yīng)位上的數(shù)字不相同時碗硬,該為才取1瓤湘,若相同,即為0恩尾。
~ 位邏輯反
>> 右移
<< 左移