2012-02-15 114 views
1

請幫我解決這個問題。接下來的步驟是表達式是:增量,增量前和增量後

//Expression 
offSpring1[m1++] = temp1; 

//步驟:

1.-增量M1

2:分配temp1中給後代

我一直認爲括號內的表達是第一個要完成的。但現在我很困惑。因此,如果這樣寫:

//Expression 
offSpring1[++m1] = temp1; 
//Steps would be: 

1.- assign temp1 to offSpring 
2.- increment m1 

如果步驟將是相同的第一批,是有什麼差別我++和++我?

回答

7
int i = 0; 
std::cout << i++ << std::endl; 
std::cout << i << "\nreset" << std::endl; 
i = 0; 
std::cout << ++i << std::endl; 
std::cout << i << std::endl; 

輸出:

0 
1 
reset 
1 
1 

i++返回值,因爲它目前矗立在表達,那麼遞增變量。 ++i將增加變量,然後返回當前表達式中使用的值。

+1

酷男!好例子。謝謝 – Guido 2012-02-15 17:24:48

0

offSpring1[m1++] = temp1;不會做你說的。

  1. 賦值temp_m1 = m1。
  2. 遞增m1。
  3. 索引offSpring1[temp_m1]
  4. temp1分配爲索引值。

在另一方面offSpring1[++m1] = temp1;是這樣工作的:

  1. 增量M1。
  2. 索引offSpring1[m1]
  3. temp1分配爲索引值。
+0

但是第2步可能發生在第4步之前或之後(在第一種情況下),我認爲根據C++ 11規則,'m1'本身可能不會在'offSpring'之後被改變(雖然使用的索引是新值,它可能尚未存儲回'm1')。 – 2012-02-15 17:25:54

+0

@BenVoigt對「offSpring」和「m1」的修改是副作用。沒有中間順序點(使用C++ 03的語言),所以它們的發生順序是未指定的。 (就此而言,如果'offSpring [m1]'碰巧指的是'm1',那麼行爲將會是不確定的。) – 2012-02-15 17:41:53

+0

@James:這正是我想要做的。你能否在我的回答中檢查我是否正確解釋了它? – 2012-02-15 17:42:57

3
offSpring1[m1++] = temp1; 

offSpring1[m1] = temp1; 
m1 += 1; 

offSpring1[++m1] = temp1; 

m1 += 1; 
offSpring1[m1] = temp1; 
1

只要運行這兩種不同的測試方案理解上的差異在後增量和增量預算

對於之間++ I(預增量)

int main() 
{ 
    int* offSpring = calloc(20,sizeof(int)); 
    int m1 =1; 
    offSpring[++m1] = 10; 
    printf("%d,%d",offSpring[m1],m1); 
} 

在第一個你將得到10作爲後代的值[M1]。 爲什麼?因爲這是預增加運算符,這意味着首先m1得到增加,其餘的得到評估。

對於i ++(後增量)

int main() 
{ 
    int* offSpring = calloc(20,sizeof(int)); 
    int m1 =1; 
    offSpring[m1++] = 10; 
    printf("%d,%d",offSpring[m1],m1); 
} 

在第二,因爲遞增運算符使用,你會得到一個0值,因爲你是第一分配10到後代[M1],然後m1得到增加。

+0

使用未指定行爲的示例非常糟糕,因爲在兩種情況下都可能獲得'10'。 – 2012-02-15 17:28:37

+0

是不是很遙遠得到10?我的意思是我在調試代碼時從未遇到過非常大的值或0。但是,當然你是正確的,爲了這個例子是完整的,我將編輯答案 – Lefteris 2012-02-15 17:30:28

0

第一個的描述是第二個的正確描述。第一個的正確描述非常相似,您只需要在其他之前添加「複製當前值m1」步驟。

但是,如果m1具有原始類型,那麼在這裏確實缺少序列點。規則在C++ 03和C++ 11之間有所變化。

如果m1有一個用戶定義的類型,那麼涉及影響排序的函數調用。


此代碼

offSpring1[m1++] = temp1; 

執行以下(如果m1是基本類型):

auto const old_m1(m1); 
auto const new_m1(old_m1 + 1); 
auto& lhs(offSpring[old_m1]); 
parallel { lhs = temp1; m1 = new_m1; } 

此代碼

offSpring1[++m1] = temp1; 

正是不同之處在於同一lhs綁定使用new_m1而不是old_m1

無論哪種情況,在m1之前或之後是否寫入lhs都未指定。

如果m1不是原始類型,它看起來更像:

auto const& index = m1.operator++(0); // one argument 
auto& lhs = offSpring.operator[](index); 
lhs = temp1; 

VS

auto const& index = m1.operator++(); // no arguments 
auto& lhs = offSpring.operator[](index); 
lhs = temp1; 

在這兩種情況下,改變m1在寫lhs之前肯定做。

+0

本,謝謝你的詳細解釋。 – Guido 2012-02-15 18:50:10

0

即使後綴增量是您的第一個示例中第一個要評估的值,它的值是要遞增的變量的原始值。

offSpring1[m1++] = temp1; 

因此,即使M1爲陣列idexing之前遞增,的temp1值在m1 - 1位置分配。

0

它的工作原理正是你所描述的相反:

offSpring1[m1++] = temp1相同 offSpring[m1] = temp1; m1 = m1 + 1;

OffSpring1[++m1] = temp1相同 m1 = m1 + 1; OffSpring1[m1] = temp1;

前綴符號的增量計算表達式 後綴表示法之前在評估表達式後遞增

+0

不,這是不一樣的。您的「等效」版本有更多的序列點。 – 2012-02-15 17:29:05

1
  • j = ++i相同i = i+1; j = i;
  • j = i++相同j = i; i = i+1;
0

有兩個方面的表達式(或子表達):它的​​價值, 和其副作用。 i ++的值是i的值; ++ i的 值爲i + 1,轉換爲i的類型。 這是表達式中使用的值。兩者的副作用是 增加變量i。這可能發生在 前面的順序點之後和下一個之前的任何時間。假設i是一個全局變量 ,你寫的東西,如:

i = 0; 
f()[i ++] = g(); 
f()[++ i] = g(); 

標準隻字未提的i值是否在f()g()看到的是,在增量之前或之後。在任何情況下。 所有的標準都說增量效應將在完整表達式開始之後(但可能作爲完整表達式的第一件事)發生,並且在結束之前發生 。 (這 他們不會用一個函數調用交錯,因此,如果f() 讀取i兩次,可以保證它看到相同的值。)

0

不幸的是,在那些2個的代碼片斷您已經發布有,沒有保證評估的順序。如果你的表情不合適,可能會發生或多或少的事情。

要開始與++和之間的差++一個:

  • 一個++將遞增一個,但使用它將會看到增量
  • ++一個將遞增一個之前的值的表達式,而使用它的表達式會看到遞增的值。
  • 列表項

buffer[a++] = b; 

編譯器可以決定做++在表達式中的任何一點。因此,如果'b'實際上是涉及a的表達式,則可以在不同的編譯器上得到不同的結果。以下兩項都是有效的:

  • 得到a的值;
  • 增量的
  • 工作出其中緩衝液[舊值]指向
  • 對b求值
  • 商店B

或該

  • 評估B;
  • 鍛鍊,其中緩衝液[一個]指向
  • 商店B
  • 增量的

如果「B」應該發生在涉及那些2個實施方式中會產生不同的結果。兩者都是有效的。