簡體   English   中英

傳遞函數參數的求值順序-F1(int F2(int&x),int x)的運算順序

[英]Order of Evaluation for passing function arguments - Order of operations for F1( int F2( int& x ), int x )

好吧,所以我早些時候寫了一些代碼。 具體來說是這樣的:

EnterNode( FindNode( terrain_X, terrain_Y, travel_dir ), travel_dir );

在測試程序后,我注意到發生了一些奇怪的事情。 外部函數接收的值不是檢查堆棧時讀取的值。

我編寫了一個示例程序: https : //ideone.com/wNjJrE

#include <iostream>

int modifyRef(int& A)
{
    A = 0;
    std::cout << "\nint& A = 0";
    return A;
}

void TakeValues(int X, int Y)
{
    std::cout << "\nX = " << X;
    std::cout << "\nY = " << Y;
}

int main()
{
    int Q = 9;
    TakeValues(modifyRef(Q), Q);
    std::cout << std::endl;
    system("pause");
    return 0;
}

這是我收到的輸出:

int& A = 0
X = 0
Y = 9

我希望Y也為0。如何將參數綁定到函數調用的操作順序定義為?

(如果我使用的術語不正確,我深表歉意。)

未指定函數參數的評估順序。 當你寫:

TakeValues(modifyRef(Q), Q);

您依賴的事實是, modifyRef(Q)Q之前要求Q 但是函數參數的求值順序未指定-不一定要在Q之前對modifyRef(Q)進行排序,反之亦然。

在這種情況下, Q (第二個參數)首先被求值。 因此,我們讀取9 ,並使用它初始化參數Y 然后 ,我們評估modifyRef(Q)其中零出Q並將其返回,導致初始化X0

嘗試更改功能的簽名:

int ModifyRef( int& A );

void TakeValues( int X, int Y );

到以下...

int& ModifyRef( int& A );

void TakeValues( int& X, int& Y );

並在調用以下代碼行時查看輸出將在main中顯示:

int q = 9;

TakeValues( ModifyRef(q), q );

然后像這樣顛倒參數的順序

TakeValues( q, ModifyRef(q) );

並比較結果。

當我在使用Intel Core2 Quad Extreme的VS2015社區的Win 7 64位計算機上執行此操作時,在使用引用的兩種情況下給出的結果都是相同的,並且得到的輸出是:

為了測試目的,我將ModifyRef()A值從0更改為7。

int& A = 7
X = 7
Y = 7

對於兩種情況,其中內部函數是第一個參數,獨立變量是第二個參數,或者內部函數是第二個參數,獨立變量為第一個參數。

由於我收到了相同的結果,對我來說似乎對編譯器創建和處理堆棧指針的方式ModifyRef()似乎首先對ModifyRef()進行了評估,並且一旦該函數完成,因為現在引用了q而不是將其作為堆棧副本,它會被ModifyRef函數中設置的任何值覆蓋。

我還稍微修改了ModifyRef()函數,以便可以看到其傳入的參數是什么,而不是將數字硬編碼到其輸出語句中。

int& ModifyRef( int& A ) {
    A = 7; // Changed Value From 0 To 7 For Testing Purposes
    std::cout << "n\int& A = " << A;
    return A;
}

但是,僅當僅使用引用時,此效果可能才適用。

當我恢復為原始函數簽名並按以下順序調用它時:

q = 9;
TakeValues( ModifyRef( q ), q );

由於您的原始代碼已顯示,因此我得到的輸出是:

int& A = 7
X = 7
Y = 9

但是,當我將參數反轉為:

q = 9;
TakeValues( q, ModifyRef( q ) );

我的輸出是:

int& A = 7
X = 7
Y = 7

因此,我在這兩種情況下看到的內容略有不同。

在參數的第一順序中,當q初始化為9時,將Y或第二個參數設置為9,並且TakeValues() Y打印出值為9的堆棧副本。然后XModifyRef()其中q的值為9,但是由於它是一個引用而被修改,因此當TakeValues()q設置X時, q已經從9更改為7,因此現在將X設置為7。

在第二個參數順序中,似乎首先調用ModifyRef()並將q從9更改為7,因此TakeValues()Y設置為7,並且由於此函數使用引用,所以q也從9更改為7。當第一個參數使用q設置X q已從9更改為7。

我不知道這是否與編譯器有關,但是至少在我的機器上,似乎參數的調用堆棧是從最右邊到最左邊發生的。 考慮到這是有意義的,因為函數具有默認值。

例:

class foo {
    void bar( int a, int b, int c = 3 ) {
        std::cout << a << ", " << b << ", " << c << std::endl;
    }
};

函數聲明中的所有默認值都必須在最右邊,因為您不能擁有:

class foo {
   void bar( int a = 1, int b, int c ) { ... } // Compile Error
};

我希望這有助於闡明當您開始使用按值(堆棧復制)或按引用傳遞時,開始在函數中調用函數作為參數時代碼中的情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM