2013-05-15 73 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