運算符與表達式
什麼是運算符?這裏舉一個例子:
int x,y //這是聲明兩個變量
x+y x-y x==y x=y
上面的“+、-、==、=”就是運算符,還有很多其他的運算符,下面我們會一一介紹。
什麼是表達式:
(x+y)*(x-y)
這就是一個簡單的表達式,無論這個表達式多麼複雜,他最後都是計算出一個結果。
不同類型表達式的計算
例如:
#include <stdio.h> //頭文件
void main() //程序入口
{
char x = 1; //把1賦給char類型的x
short y = 3; //把3賦給short類型的y
int z = x+y; //把x+y返回到int類型的z裏
printf("%d\n",z); //以十進制輸出結果到控制檯
return; //程序結束
}
這裏是兩個變量x,y外加一個返回值z,它們分別是三個類型:char、short、int,那麼他們是怎麼運算的,我們直接去反彙編看一下就行了:
這裏可以看到,程序把x的值存到了eax中,把y的值存到了ecx中,這兩個寄存器都是四個字節的,也就是說,在進行相加之前先轉換成了int類型,那麼int類型又是四個字節,也就是先統一類型,再進行計算,這裏統一類型是有先後級的。
char < short < int < float < double
這裏總結一下:
- char類型跟short類型運算,最後都會轉爲int類型。
- 計算最終結果的類型由表達式中數據寬度最大的那個變量決定。
常見的運算符
算術運算符
+ - * / % ++ --
加減乘除、取餘、自加、自減
這裏我們主要說一下這個++、–,先上一段代碼:
#include <stdio.h> //頭文件
void main() //程序入口
{
int x = 1; //把1賦值給int類型的x裏
x++; //在當前x的值的基礎上加1
printf("%d\n",x); //以十進制輸出結果到控制檯
return; //程序結束
}
運行結果:
那麼++是自加1,–自然就是減1了:
#include <stdio.h> //頭文件
void main() //程序入口
{
int x = 1; //把1賦值給int類型的x裏
x--; //在當前x的值的基礎上減1
printf("%d\n",x); //以十進制輸出結果到控制檯
return; //程序結束
}
運行結果:
這個 ++與–可以放在變量前與變量後,放前放後計算出來的結果都是一樣的,但是執行順序有所不同:
++在前,先自加在進行計算。
++在後,先進行計算再自加。
改一下代碼:
#include <stdio.h> //頭文件
void main() //程序入口
{
int x = 1; //把1賦值給int類型的x裏
x++; //x自加1
int y = x; //把x的值賦給y
printf("%d\n",y); //輸出結果到控制檯
return; //程序結束
}
運行結果:
反彙編看一下是怎麼傳值的:
先看這兩行代碼:
int x = 1;
x++;
這是它的彙編指令:
mov dword ptr [ebp-4],1
mov eax,dword ptr [ebp-4]
add eax,1
mov dword ptr [ebp-4],eax
先把1賦給ebp-4,再把ebp-4賦給eax,隨後eax再加1,再把1賦值給ebp-4,這一波操作之後x的值就是2了。
接着是這兩行代碼:
int y = x;
printf("%d\n",y);
這裏把2又賦值給了eax,接着把eax賦給ebp+8,接着又把ebp-8賦給了eax,然後eax壓棧,輸出結果。
mov eax,dword ptr [ebp-4]
mov dword ptr [ebp-8],eax
mov eax,dword ptr [ebp-8]
push eax
push offset string "%d\n" (00422fa4)
call printf (00401
090)
add esp,8
再來看看++在前會是什麼樣的結果:
#include <stdio.h> //頭文件
void main() //程序入口
{
int x = 1; //把1賦值給int類型的x裏
printf("%d\n",++x); //進行自加然後輸出結果到控制檯
return; //程序結束
}
反彙編:
這裏可以清楚的看到,程序是先進行了自加,在計算的結果,然後輸出,這就是++在前與在後的區別,–同理。
關係運算符
< <= > >= != ==
小於、小於等於、大於、大於等於、等於、不等於
關係運算符的值只能是0和1
關係運算符的值爲真時,結果爲1
關係運算符的值爲假時,結果爲0
例子:
#include <stdio.h> //頭文件
void main() //程序入口
{
int a = 10; //賦值
int b = 20;
int c = a<=b; //把a<=b的結果返回給c
if(a<=b) //進行判斷
{
printf("正確!\n"); //輸出判斷結果
}
else //否則輸出另一種結果
printf("錯誤!\n");
return; //程序結束
}
看一下運行結果:
爲什麼說結果只有0和1呢?下個斷點看一下C裏的值就知道了:
如果正確就是1,跟我們程序運行後的結果一致(結果爲真)。
邏輯運算符
&& || !
與、或、非
x>y && x<z 只有一個結果
x>y || x<z 只有一個結果
例子:
#include <stdio.h> //頭文件
void main() //程序入口
{
int x = 10; //賦值
int y = 20;
int z = 30;
int r = x>y && x<z; //進行與運算,兩數相與,同真則真
return; //程序結束
}
我們去反彙編看一下r的值是多少:
值爲0,很明顯這是正確的。
位運算符
<< >> ~ | ^ &
左移、右移、非、邏輯或、異或、邏輯與
例子:
x = 1
y = 2
//與運算,相對應的位都爲1的時候,結果才爲1
0000 0001
0000 0010 &
-----------
0000 0000
//或運算,相對應的位只要有一個爲1,結果就爲1
0000 0001
0000 0010 |
-----------
0000 0011
//異或運算,只有兩個位不一樣的時候,結果爲1,反之爲0
0000 0001
0000 0010 ^
-----------
0000 0011
//非運算,取反即可
0000 0001 ~
-----------
1111 1110
用程序驗證一下:
#include <stdio.h> //頭文件
void main() //程序入口
{
int x = 1; //賦值
int y = 2;
printf("與運算:%d\n",x&y); //輸出相對應的結果
printf("或運算:%d\n",x|y);
printf("異或運算:%d\n",x^y);
printf("非運算:%d\n",~x);
return; //程序結束
}
運行結果:
賦值運算符
= 拓展賦值
例子:
#include <stdio.h> //頭文件
void main() //程序入口
{
int z = 1; //把1賦值給z
z += 2; //相當於 int z = z+2;
printf("%d\n",z) //輸出結果
return; //程序結束
}
運行結果:
運算符的優先級
這裏的優先級跟小學數學一樣,先算乘除,再算加減,有括號先算括號裏的。
例子:
#include <stdio.h> //頭文件
void main() //程序入口
{
int x; //聲明變量
x = 2+3*4-8/2 //賦值
printf("%d\n",x); //輸出結果
return; //程序結束
}
運行結果: