C 在函式引數中使用 與 運算子

2021-09-27 13:53:18 字數 1625 閱讀 8605

進行c++的學習有一段時間了,今天做練習的時候遇到了乙個在函式引數中使用帶有++運算子表示式的問題,稍微研究了一下發現用到的知識點還不少,挺有意思的,這裡正好進行下總結擴充套件,順便梳理一下最近學到的知識。由於遞增運算子++與遞減運算子–的機制完全一致,以下僅以++為例進行討論,–同理。

以下程式的執行結果是什麼呢?

#include

using

namespace std;

void

foo(

const

int&a,

const

int&b,

const

int&c)

intmain()

答案是4 4 43 2 1,有沒有覺得意外呢?其實只要理解了++運算子的使用方式和c++的函式呼叫慣例,這個問題非常好解釋。

++是個神奇的一元運算子,根據它位置的不同,有前置版本和後置版本兩種形式。雖然最終效果都是使變數進行自增1的運算,但是這這兩種版本的返回值和執行機理卻大不相同。假設我們有乙個整形變數int i,根據《c++primer》,前置版本與後置版本區別如下:

如此一來,數值的問題便可以解釋了。

問題似乎解決了,但是仔細想想還是有些奇怪:為什麼foo(b++, b++, b++)的輸出順序是3 2 1呢?這說明我們實際呼叫的是foo(3, 2, 1),為什麼會這樣呢?要解釋這個問題,那就要稍微提一下c++的函式呼叫慣例了。

這部分內容只做大致說明,不做詳細講解,詳情可參閱《程式設計師的自我修養》。簡單來說,為了正確呼叫函式,函式的呼叫方和被呼叫方對於函式如何呼叫需要有乙個明確的約定,這樣的約定就稱為呼叫慣例。呼叫慣例規定了許多函式呼叫時的規則,其中有一項與我們的問題息息相關,那就是函式引數的傳遞順序

c++預設的呼叫慣例是cdecl,它規定引數的傳遞順序為從右至左壓引數入棧。因此,foo(b++, b++, b++)實際上最先對最右邊的b++表示式進行求值,然後處理中間的,最後處理最左邊的,所以我們實際呼叫的是foo(3, 2, 1)

這下問題總算是徹底解決了。順便,foo(++a, ++a, ++a)的順序當然也是從右至左的,只不過最後實參都是&a,反映不出順序的問題罷了。

*修訂:編譯器有權在不致錯誤的情況下重新排列同乙個語句中各表示式的執行順序,因此函式實參表示式的計算並不一定是嚴格從右至左的,參見《effective c++》條款17。

再順便複習一下引用的相關知識。因為++b返回的是乙個臨時量右值,普通引用是繫結不了的,因此如果foo的引數型別為int&b++這種後置遞增表示式是不能當實參的。而因為常量引用具有能夠繫結字面值的特殊性質,所以引數型別為const int&時可以用b++作為實參。

C語言在 define中使用 運算子和 運算子

下面是乙個類函式巨集 define psqr x printf the square of x is d.n x x 如果這樣使用巨集 psqr 8 則輸出為 the square of x is 64.引號中的字串中的x被看作普通文字,而不是被看作乙個可被替換的語言符號。1 利用巨集引數建立字串 ...

C 基礎(六)在物件中使用運算子 運算子過載

c 語言允許程式設計師重新定義已有的運算子,使其能夠按使用者的要求完成一些特定的操作,這就是運算子過載。經過載後的運算子過載。經過載後的運算子能夠直接對使用者自定義的資料進行操作運算。本章介紹有運算子過載方面的內容。c 語言為實現運算子過載提供了一種方法,即將運算子看作一種特殊型別的函式,運算子過載...

C語言 運算子與 運算子

我們平時使用帶參巨集時,字串中的巨集引數是沒有被替換的。例如 輸出結果為 然而,我們期望輸出的結果是 5 20 2513 14 27 這該怎麼做呢?其實,c語言允許在字串中包含巨集引數。在類函式巨集 帶參巨集 中,號作為乙個預處理運算子,可以把記號轉換成字串。例如,如果a是乙個巨集形參,那麼 a就是...