从整数转换为整数的方法有区别吗?

时间:2013-05-15 14:12:29

标签: c# c++ casting bit-manipulation d

当我想将整数(例如32位整数/ int)转换为另一个整数类型(例如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的答案。

我也忘记了我的意思是无符号整数(没有签名)。所以它适用于所有无符号整数类型。

2 个答案:

答案 0 :(得分:3)

在C#中,如果int超出checked上下文中的范围,则将int转换为字节将引发异常。否则,强制转换就像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 
}

Versus

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 
}

对于ANDing:

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);
}

奇怪的是,第一个给出编译器错误,即使默认情况下它在运行时未经检查。我猜默认会检查编译时间!

答案 1 :(得分:0)

在C ++中,获得结果的方式完全不同,因为&的操作数将被提升为两种类型中较大者的大小。如果您&的“最大”值恰好是签名的,那么您将签署扩展,并且按位操作将不太可能具有所需的效果。

我个人更喜欢明确的return static_cast<char>(value);