2013-05-15 75 views
0

當我想將整數(例如32位整數/整數)轉換爲另一整數類型(例如8位整數/字節)時,是否有區別。以下是我可以將其轉換爲兩種方式的一些示例代碼:從整數轉換爲整數有什麼不同嗎?

byte foo(int value) 
{ 
    //return value; <-- this causes problems because I need to convert it to byte 

    //First way(most people use this): 
    return (byte)value; //this involves casting the value and also works if value is floating point type 

    //Second way: 
    return value & byte.MaxValue; //byte.MaxValue is a constant that is 255 
} 

那麼兩者之間有什麼區別嗎?我知道按位操作只適用於整數類型。我知道第二種方式不太可讀或不推薦。除此之外,兩種方式的輸出都不相同。這不僅適用於int和byte,而且適用於每個整數整數類型的組合。

好吧,看來這個操作在不同的語言中有不同的行爲。我不想看到差異,所以請發佈C++/C#/ D的答案。

此外我忘了我的意思是隻有無符號整數(沒有簽名)。所以它適用於所有的無符號整數類型。

+0

什麼是「字節」?編輯:哦,它也被標記爲C#。每種語言的答案可能會有所不同。 –

+0

對於每種語言,它並不會讓我感到不同。這更多是一個理論問題。 – Bosak

+0

@Bosak:不管它對你有沒有意義,它都*取決於語言。不同的語言可以有不同的規則。例如,在C#中,如果您處於選中的上下文中,強制轉換可以拋出異常*。 –

回答

3

在C#中,鑄造一個int爲一個字節將拋出一個異常,如果它超出範圍一個checked範圍內。否則,投射就像C++一樣。

C#中的類型提升與C++類似(如Mark B所述)。

爲了進行比較,看看這三個方法產生的IL:

byte foo1(uint value) 
{ 
    return (byte) value; 
} 

.method private hidebysig instance uint8 foo1(int32 'value') cil managed 
{ 
    .maxstack 8 
    L_0000: ldarg.1 
    L_0001: conv.u1 
    L_0002: ret 
} 

對戰

byte foo2(uint value) 
{ 
    checked 
    { 
     return (byte)value; 
    } 
} 

.method private hidebysig instance uint8 foo2(uint32 'value') cil managed 
{ 
    .maxstack 8 
    L_0000: ldarg.1 
    L_0001: conv.ovf.u1.un 
    L_0002: ret 
} 

而對於與運算:

byte foo3(int value) 
{ 
    return (byte)(value & byte.MaxValue); 
} 

.method private hidebysig instance uint8 foo3(uint32 'value') cil managed 
{ 
    .maxstack 8 
    L_0000: ldarg.1 
    L_0001: ldc.i4 255 
    L_0006: and 
    L_0007: conv.u1 
    L_0008: ret 
} 

這再次使用conv.u1,像第一種方法,所以它所做的就是引入額外的比特的開銷無論如何由conv.u1指令。

因此,在C#中,如果您不關心範圍檢查,我只會使用該投射。

一個有趣的事情是,在C#中,這會給你一個編譯器錯誤:

Trace.Assert(((byte)256) == 0); // Compiler knows 256 is out of range. 

這不會給編譯錯誤:

int value = 256; 
Trace.Assert(((byte)value) == 0); // Compiler doesn't care. 

當然,這將不給編譯錯誤:

unchecked 
{ 
    Trace.Assert(((byte)256) == 0); 
} 

奇怪的是,第一個給出編譯器錯誤,即使通過脫髮它在運行時沒有被選中。我猜編譯時間是默認檢查!

+0

然後如果我同時執行'(byte)(value&byte.MaxValue)',會發生什麼?它會確保它永遠不會超出範圍嗎? – Bosak

+0

@Bosak是的,這將確保演員在檢查的上下文中不會失敗。 –

+0

@DanielFischer謝謝,修正。 :) –

0

在C++中,獲得結果的方式完全不同,因爲操作數&將被提升爲兩個類型中較大值的大小。如果您發現&的「max」值恰好是有符號的,那麼您將簽名擴展,並且按位操作不可能具有所需的效果。

我個人比較喜歡明確return static_cast<char>(value);

+0

哦,對不起,我沒有提到我的意思是無符號整數 – Bosak