1. 程式人生 > >C語言中++、-- 及編譯器的貪心法

C語言中++、-- 及編譯器的貪心法

C語言中的++、–即自增、自減是很令人頭疼的。 剛好看到一個問題,一起分析一下。

int i = 3;
(++i) + (++i) + (++i);

你覺得這個表示式的值是多少? 如果你覺得是15,那完了,你c語言學的跟我一樣,太爛了。 我去查了一下,有說是16,還有說是18的。分析了一下,好像都有道理。 如果是都先做完括號內的,那答案就是18了。 但編譯器如果認為前兩個括號做完,然後會認為後面是加號,和前面一樣的,前面兩個便可以先進行計算,結果就是16。 分析完了,就直接去執行看結果吧,我使用了gcc和g++編譯,結果都是16。後來問大佬,查資料,據說這是c語言的灰色地帶,沒有明確規定,結果會因編譯器規則不同而不同。

繼續看另一段程式碼:

#include <stdio.h>

int main()
{   
    int i = 0;
    int j = ++i+++i+++i;//報錯1
    
    int a = 1;
    int b = 2;
    int c = a+++b;
    
    int* p = &a;
    
    b = b/*p;//報錯2
      
    return 0;
}

你覺得j的結果是多少? 實際是這裡會報錯,

[Error] lvalue required as increment operand

說左值不可以增運算,為什麼報這錯呢?因為編譯器是貪心法閱讀

程式碼: 編譯器處理的每個符號應該儘可能多的包含字元 編譯器以從左向右的順序一個一個儘可能多的讀入字元 當即將讀入的字元不可能和已讀入的字元組成合法符號為止 所以看上面的j那一行可分析到一次讀,會一直讀到++i++為止,我們知道++i返回是值,值自然不可以進行運算,所以報錯。我們通常應該加上括號,已明確運算順序。

修改之後,再編譯,發現上面的第二個報錯,這個又為什麼報錯呢,如果用ide編輯程式碼,就會發現從/*開始都認為是註釋了。就是我們之前提到的編譯器的貪心法了,認為是註釋開頭了。

對此,通常程式設計規範中都會有規定,對於運算都明確加括號以明確運算順序。另外就是我們會發現,使用很多ide程式設計的時候,在我們例如加上結束符之後,會幫我們格式化,這時你都會發現運算物件和運算子之間都會有空格,其實這不光光是美觀,編譯器會識別空格,知道這裡是讀入結束。 瞭解了這些知識,修改上面的程式碼:

#include <stdio.h>

int main()
{   
    int i = 0;
    int j = ++i+ ++i+ ++i;
    
    int a = 1;
    int b = 2;
    int c = a+++b;
    
    int* p = &a;
    
    b = b/ *p;
      
    return 0;
}

不光看的清晰,編譯執行完美了。