1。如何重新解释将float转换为int(或将double转换为long)?
float f = 2.0f;
int i = (int)f; // causes conversion
我只想把比特模式从f
复制到i
。如何做到这一点?
2。C#中的隐式和显式运算符使用一个中间对象,因为运算符函数是静态
public static implicit operator MyClass(double s)
{
return new MyClass(s);
}
..
..
MyClass m = 2.2; // this code uses 'm' and one intermediate object.
这对于引用类型来说很好,但对于较大的值类型(比如20-30字节),这将导致不必要的数据复制。我的理解正确吗?如果是,那么为什么C#没有一个非静态的转换运算符或用户定义的赋值运算符,以便在"this"上进行转换/赋值?如果是这样,怎么办?
1:BitConverter(作为六个字母的变量)是一个选项;不安全代码也是如此(不需要中间缓冲区):
float f = 2.0f;
int i;
// perform unsafe cast (preserving raw binary)
unsafe
{
float* fRef = &f;
i = *((int*)fRef);
}
Console.WriteLine(i);
// prove same answer long-hand
byte[] raw = BitConverter.GetBytes(f);
int j = BitConverter.ToInt32(raw, 0);
Console.WriteLine(j);
2:注意你应该限制structs的大小。我找不到它的引文,但数字"16字节"(最大值,作为建议)似乎一直萦绕在我的脑海中。在此之上,考虑一个不可变的引用类型(类)。
禁止不安全的代码-这是我所知道的执行重新解释的最快方法:
[StructLayout(LayoutKind.Explicit)]
private struct IntFloat
{
[FieldOffset(0)]
public int IntValue;
[FieldOffset(0)]
public float FloatValue;
}
private static float Foo(float x)
{
var intFloat = new IntFloat { FloatValue = x };
var floatAsInt = intFloat.IntValue;
...
希望这能帮助到别人。
-
BitConverter类可以检索任何基元类型的字节,然后可以使用这些基元创建int。如果要进行大量转换,另一个选项是Buffer.BlockCopy。
float ff = 2.0f; int ii = BitConverter.ToInt32(BitConverter.GetBytes(ff), 0); float[] ff = new float[...]; int[] ii = new int[ff.Length]; Buffer.BlockCopy(ff, 0, ii, 0, ff.Length * 4); // byte-wise copy of ff into ii
-
不,在C#中没有给出其他选项,但是,我认为,虽然您在将要创建副本的意义上是正确的,但任何足够简单的实现都将进行JIT优化,可能会消除对副本的需要。
这种方法虽然不安全,但可以作为通用解决方案
static unsafe TDest ReinterpretCast<TSource, TDest>(TSource source)
{
var tr = __makeref(source);
TDest w = default(TDest);
var trw = __makeref(w);
*((IntPtr*)&trw) = *((IntPtr*)&tr);
return __refvalue(trw, TDest);
}
这应该是最快、最干净的方法:
public static class ReinterpretCastExtensions {
public static unsafe float AsFloat( this int n ) => *(float*)&n;
public static unsafe int AsInt( this float n ) => *(int*)&n;
}
public static class MainClass {
public static void Main( string[] args ) {
Console.WriteLine( 1.0f.AsInt() );
Console.WriteLine( 1.AsFloat() );
}
}