【问题标题】:Casting in D - type coercion: preserving bit pattern, without value conversionsD型强制转换:保留位模式,没有值转换
【发布时间】:2017-06-22 12:15:49
【问题描述】:
我想将值的类型转换为宽度完全相同的无符号整数,并保留确切的位模式。因此,例如 64 位浮点数将被键入为 ulong,但位模式将是相同的。输入类型未指定,但我不需要处理大于通常 D 整数类型之一的输入值,因此没有聚合或内存对象。
我首先尝试生成一种无符号整数类型,可以就如何正确执行此操作提出建议,因为我应该就如何处理常量性和不变性做出一些决定输入类型。
-
然后在获得合适的类型后,我强制编译器通过执行类似的操作来避免值转换
( * cast(const T_uint_result *) & input_val )
检查了生成的代码后,这似乎可行,但我对此非常不满意。很多时候直接强制转换就可以了,但是对于我的目的来说这通常是不安全的,因为编译器可能会更改位模式。
【问题讨论】:
标签:
casting
type-conversion
d
type-coercion
【解决方案1】:
我很确定除了您发布的解决方法之外没有内置的方法可以做到这一点。您可以做的是为您编写一个函数,如下所示:
pragma(inline, true)
T bitCast(T, Orig)(scope Orig val) pure nothrow @nogc @system {
return *(cast(T*) &val);
}
这样使用:
float f = 4.5f;
uint i = f.bitCast!uint;
writeln(i); // 1083179008
更安全的替代方法是使用联合,但您需要确保确实在那里使用了正确的类型,否则由于宽度不同(浮点/双精度转换),与上面的函数相比,该值可能是其他值:
union DoubleLong {
double value;
long integer;
}
否则,如果您的目标实际上是获取或设置浮点数或双精度数的分数、指数和符号,您不妨使用std.bitmanip.FloatRep 或std.bitmanip.DoubleRep
在那里你也可以操作这些部分,用法是这样的:
FloatRep fr;
fr.value = 4.5f; // your float here
fr.exponent = fr.exponent - 1; // reduces exponent, it's a property, so no unary operators
writeln(fr.value); // 2.25, it's divided by 2 because it's binary
【解决方案2】:
您可以只使用union。例如
union U
{
float f;
uint i;
}
U u;
u.f = input;
output = u.i;
如果你想要一个函数,你可以做类似的事情
import std.algorithm;
auto reinterpretAsInteger(T)(T t)
if([1, 2, 4, 8].canFind(T.sizeof))
{
union U
{
T input;
static if(T.sizeof == 1)
ubyte output;
else static if(T.sizeof == 2)
ushort output;
else static if(T.sizeof == 4)
uint output;
else static if(T.sizeof == 8)
ulong output;
}
U u;
u.input = t;
return u.output;
}