首頁>Club>
17
回覆列表
  • 1 # 使用者7195217773096

    因為"++"是C語言定義的運算子,是被C語言編譯器支援的,能被按照其規定邏輯編譯的運算子。其語意就是一個變數自增,如果"++"在後則當前語句結果為自增前的值,從下條語句開始變數為自增後的值。如果"++"在後則當前語句的結果就是自增後的值。

    比如,一個單行的“i++”可能就編譯為:

    而一行a=i++可能就編譯為:

    這些都是編譯器根據++運算子的語意編譯出來的,你非要問它為什麼這樣,那它就是這麼定義的,編譯器也就是按照這個規則編譯它的。

    就像老師說明天考試,你非要問老師“為什麼明天要考試?”老師說“我就是要測驗你們啊”,你還矯情問老師“為什麼你就要明天測驗我們?我能理解你明天讓我們放假,但是你非讓我們考試,我覺得你可能看我們不爽所以非要明天測驗我們。而我猜測你也可能是失戀了,拿我們出氣”…… 如果你覺得荒謬,那我告訴你,C語言編譯器如果面對你題目中的問題,就像老師面對一個這樣的學生一樣。

    重點補充:

    C語言執行a=a++;後a的值應該加一還是不變?

    所以我當時一時覺得這些都是差不多的問題(其實也是有聯絡的,我下面說),就匆匆看了一下題目然後回答了一下這個問題睡覺了。因為關注的人不多,所以我也沒怎麼回看這個問題,直到李海怪同學提醒我題主想問的是"i++"為什麼在運算結束後還能“返回”一個值?

    不過針對如此,我上面其實沒有說錯(不過側重點沒往這上解釋),這確實就是這麼設計的,也確實是沒有為什麼“一定”要這麼設計的原因:)

    下面針對i++為什麼會有“返回”我重新補充一下,以下是我的純“個人觀點”,沒有準確的原作者依據:

    其實不止i++這樣的表示式有“返回值”,很多賦值語句(如a=b+1)都有“返回值”(注意這裡返回值加了引號,因為它不是真正意義的返回值)關於C以及C衍生的語言為什麼賦值表示式可以“返回”一個值,我已經找不到真實原因的考據了,如果誰找到當初設計原稿的作者原述請告訴我,感激不盡。我們現在也不能把丹尼斯里奇找出來問,但是將其歸結為設計失誤是莽撞的(有點太看不起一代大師級人物了)。這確實是C語言的設計,而不是單純“失誤”造成的,頂多你可以覺得它有好有弊,所以有人不贊同這樣設計是絕對好的設計。

    一個人,特別是一個(真)大師級別的人,很多設計都應該是有其思想支撐的(就像補碼的設計,這裡推薦 @三郎 寫的這篇三郎:計算機數學小書1-原碼,反碼和補碼,可以看一下我們認為“自找麻煩”的補碼是為什麼那樣設計)。那麼丹尼斯里奇作為一代大師中的大師,他為什麼要讓很多賦值表示式有一個“返回值”呢?

    我覺得丹尼斯先生可能是想體現“我可以不間斷的使用我剛賦值的值”這種想法(個人猜測,沒有證據)。比如我可以b = c = a + 1,我可以a=i++ , 我還可以while((*d++ = *s++) != 0),我也可以if ((len=strlen(str) + 1) > count),等等等等。我覺得他可能就是希望我可以這樣來使用(當然並不是推薦優先這麼寫,C語言很多時候只是提供給我們方法,怎麼用是程式設計者的責任。

    說完為什麼賦值表示式會有“返回值”的設計後,我們就說一下這個值是什麼。

    首先這不是一個真正意義上的“返回值”,一個賦值表示式並沒有返回值。只是在將其和更多運算混用(或者說在一個表示式裡需要引用其結果時)這個“返回值”才會被編譯器預留。而預留的一般不是左值,而是右值(這裡請不要把這條作為程式設計標準依據)。

    比如

    實際上是a + 1的結果被儲存下來,賦值給c,又接著作為"返回值"給b=的表示式使用。如下面這段程式:

    其未經過最佳化的純存結果是(省去部分不重要內容):

    可以看到a=33;b=c=a+1;兩條語句就是下面這幾行:

    可以看出,編譯器是先用eax儲存的了a+1的值,然後將eax的值給c,又將c在記憶體中的值給eax暫存器,再將eax的值給b。這整個過程eax都充當了“返回值”。

    如果還不夠,我可以激進一點,寫成:

    編譯結果為:

    所以說這個“返回值”就是C語言對這種行為的支援。它就是想做到這種連貫的對於賦值的使用。它是賦值表示式的右面的結果被儲存在一個地方後下面繼續被使用的現象。而像i++這樣的表示式更是其特殊運算子下的特殊“賦值”表達,很難用一行賦值表示式表達出來,但是編譯器確是可以理解其正確意思,即在需要“返回值”時先儲存i的值,然後讓i的值加1覆蓋i原來的值,則“返回”儲存的原值。不需要“返回值”(單行i++)時則不必要預先保留原值。設計就是這樣的,編譯器也都是按照這樣的邏輯解釋的。

    那麼我開始提到的a=22;a=a++;的問題,為什麼有的地方結果是22,有的地方結果是23呢。就是表示式的“返回值”和a++後a的值是兩個不同位置。我原文中提到了,a=22;a=a++的編譯結果“有時”是:

    我們可以看出其實eax是儲存的a++要“返回”的結果,然後編譯器轉而用edx去繼續計算a+1後的結果。然後a++是一個帶賦值語句,a=...也是一個賦值語句。那麼“這裡”就是在完成計算部分後,先完成a++的最後賦值,再完成a=(a++的返回值)的賦值。當然這種邏輯是沒有得到保證的,具體還是回看我回答a=a++那個問題的描述。

    那麼回看題主的問題:

    i++為啥會有值

    答:i++是不是有“返回”值取決於你是否在一個表示式中“引用”(i++)的結果。單純的一行i++,編譯器是不會預留“返回值”的。只有在需要(i++)的結果時,C語言支援持續連貫的賦值表示式結果使用,即讓編譯器另外臨時儲存計算結果(其別於表示式左值的儲存位置),給後續使用。

    另外我提議問題是不是可以改的更明確一點,比如(拋磚引玉):C語言的賦值表示式,如i++, (i=i+1),為什麼會有“返回”值?

    以上純屬個人理解,如有雷同純屬巧合。如果有不同,也很正常:-)

    更多與專業有關內容,請參考:

    醉臥沙場:README - 專業性文章及回答總索引

  • 中秋節和大豐收的關聯?
  • 單獨撫養決定權和撫養權有什麼區別,中美兩國的法律有這個概念嗎?