当我想将一个整数(例如 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 的答案。
另外我忘了我的意思是仅无符号整数(未签名)。所以它适用于所有无符号整数类型。
最佳答案
在 C# 中,如果它在 checked
上下文中超出 and 范围,则将 int 转换为 byte 将引发异常。否则,转换的行为与 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
}
对于 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);
}
奇怪的是第一个给出了一个编译器错误,即使默认情况下它在运行时是未检查的。我想默认情况下会检查编译时!
关于c# - 从整数到整数的转换方式有区别吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16567424/