2017-01-18 127 views
1

所以我正在玩類型和我下面出現這個奇怪的結果。調試它沒有意義,然後唯一的結果是檢查出C++ spects,這沒有太大的幫助。我想知道你是否可能完全知道這裏發生了什麼,如果它是32Bit和/或64Bit的特定問題。unsigned int/signed int/long long:莫名其妙的輸出

#include <iostream> 
using namespace std; 

int main() { 
    unsigned int u = 1; 
    signed int i = 1; 

    long long lu = -1 * u; 
    long long li = -1 * i; 

    std::cout<<"this is a weird " << lu << " " << li << std::endl; 

    return 0; 
} 

當輸出是

this is a weird 4294967295 -1 
+3

@George這不是未定義的行爲,因爲這是無符號整數溢出 – DarthRubik

回答

5

關鍵的觀察結果是表達-1 * uunsigned int類型。這是因爲算術轉換的規則說如果一個操作數是unsigned int而另一個是signed int,那麼後面的操作數是轉換成unsigned int。算術表達式最終只針對同類操作數定義,所以轉換髮生在操作正確之前。

-1轉換爲unsigned int的結果是一個很大的正數,表示爲long long int,這是您在輸出中看到的數字。

目前,這是[expr] /(11.5.3)。

+0

謝謝你Kerrek! –

+0

@ShanyG:我的榮幸:-) –

+0

@ShanyG:對於本質,我讓Kerrek SB成爲這個網站上最聰明的人。 Hans Passant同樣在Windows C++的東西上。 – Bathsheba

1

-1 * i

的評價是二int類型的瑣碎乘法:沒什麼可奇怪的存在。而long long必須能夠容納任何int


首先說明是有與在C++負字面沒有這樣的事情,所以

-1 * u

作爲(-1) * u由於操作者的優先級進行評價。 (-1)的類型必須是int。但是,由於C++的參數轉換規則,這將被轉換爲unsigned int,因爲另一個參數是unsigned int這樣做的話,它被模UINT_MAX + 1模轉換,所以你最終以UINT_MAX乘以1,這是你觀察到的數字,儘管轉換爲一個long long類型。

最後要注意,這個轉換的行爲是受到轉換從unsignedsigned類型的規則:如果unsigned intlong long是你的平臺上都爲64位,則行爲是實現定義的。

+1

現在我完成了,非常謙虛,並且在我退休時,會讓您作爲我公司的顧問前進。 – Bathsheba

+1

我期待收到未簽署的合同:-) –

+0

我認爲*(但仔細檢查)轉換回簽名的方式永遠不是UB;它是實現定義的。什麼是UB就像簽名類型的'a + b'。 –

1

-1的類型是signed int。當您在不同基本類型的對象之間執行算術運算時,一個或兩個參數將被轉換,以便兩者具有相同的類型。 (對於非基本類型,混合操作數可能會有操作符重載)。在這種情況下,符號值將轉換爲無符號,遵循轉換規則

因此,-1被轉換爲無符號。但負數不能用無符號類型表示。發生的情況是,結果值將是可以由無符號類型表示的最小正值,即與原始有符號值相匹配,並以無符號類型表示的最大值爲模。哪個平臺上正好是4294967295


規則([EXPR],標準草案):

...適用於非整數規則...

否則,積分優惠(4.5)應在兩個operands.61進行再下面 規則應被施加到推動操作數:

- 如果兩個操作數具有相同類型,則不需要進一步轉換。 - 否則,如果兩個操作數具有有符號整數類型或兩者都具有無符號整數類型,則具有較小整數轉換等級類型的 操作數應轉換爲具有更高等級的 操作數的類型。

- 否則,如果具有無符號整數類型的操作數的秩大於或等於另一個操作數的類型的 秩,用符號整型操作數須轉換到 操作數與該類型無符號整數類型。 (適用於你的情況)

- 否則,如果有符號整數類型的操作數的類型,可以表示所有的 無符號整型操作數的類型的值,用無符號整型操作數應將 轉換爲帶符號整數類型的操作數的類型。

- 否則,兩個操作數將轉換爲無符號整數類型,對應於帶有符號整數類型的操作數的 類型。

+0

一般來說,「其中一個參數將被轉換爲另一個類型」並不正確。一般而言,「這兩個論點都可以轉化爲某種類型」。見[expr] /(11.5.5)。 –

+0

@KerrekSB謝謝,希望現在的措辭更好。 – user2079303

+0

這仍然不正確。轉換的類型也可以被簽名,例如,見[expr] /(11.5.4)。 –

0

當解釋爲32b有符號整數時,位模式「0xFFFFFFFF」對應於「-1」,當解釋爲32b無符號整數時,對應於「4294967295」。

  • 如果使用-2的結果是 「4294967294」
  • 如果使用-3的結果是 「4294967293」
  • 如果使用-4的結果是 「4294967292」
  • ....