C語言從基礎(chǔ) -> 精通 -> 底層 (4) 運算符與類型轉(zhuǎn)換

一、算術(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);
運行結(jié)果

三击困、關(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恩尾。
~ 位邏輯反
>> 右移
<< 左移
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末弛说,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子翰意,更是在濱河造成了極大的恐慌木人,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冀偶,死亡現(xiàn)場離奇詭異醒第,居然都是意外死亡,警方通過查閱死者的電腦和手機进鸠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門稠曼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人客年,你說我怎么就攤上這事霞幅∧牵” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵司恳,是天一觀的道長途乃。 經(jīng)常有香客問我,道長扔傅,這世上最難降的妖魔是什么耍共? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮铅鲤,結(jié)果婚禮上划提,老公的妹妹穿的比我還像新娘。我一直安慰自己邢享,他們只是感情好鹏往,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著骇塘,像睡著了一般伊履。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上款违,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天唐瀑,我揣著相機與錄音,去河邊找鬼插爹。 笑死哄辣,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的赠尾。 我是一名探鬼主播力穗,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼气嫁!你這毒婦竟也來了当窗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤寸宵,失蹤者是張志新(化名)和其女友劉穎崖面,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體梯影,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡巫员,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了甲棍。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疏遏。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出财异,到底是詐尸還是另有隱情,我是刑警寧澤唱遭,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布戳寸,位于F島的核電站,受9級特大地震影響拷泽,放射性物質(zhì)發(fā)生泄漏疫鹊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一司致、第九天 我趴在偏房一處隱蔽的房頂上張望拆吆。 院中可真熱鬧,春花似錦脂矫、人聲如沸枣耀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捞奕。三九已至,卻和暖如春拄轻,著一層夾襖步出監(jiān)牢的瞬間颅围,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工恨搓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留院促,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓斧抱,卻偏偏與公主長得像常拓,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子夺姑,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345