我试图将带符号的浮点变量转换为DWORD ... DWORD将被另一个程序使用,因此DWORD变量类型很重要...
首先......签名的DWORD可以解释为无符号的DWORD ..?
还...我怎样才能将签名的浮点数转换为DWORD(签名)..?
我试图将带符号的浮点变量转换为DWORD ... DWORD将被另一个程序使用,因此DWORD变量类型很重要...
首先......签名的DWORD可以解释为无符号的DWORD ..?
还...我怎样才能将签名的浮点数转换为DWORD(签名)..?
DWORD是Windows API定义的32位无符号整数类型.没有"签名的DWORD"这样的东西.可能你的意思是相应的签名类型.
在C++中所有浮点类型(float,double和long double)签署的类型,所以这是不寻常的谈"签署浮点".大概你的意思是它可以是负值.将负浮点值转换为无符号整数有两种主要可能性:
好像浮点值,比如说-1.23,转换为有符号整数,然后调整2 n的合适倍数,使其进入无符号整数范围,或者
好像浮点值再次说-1.23是通过2 n的适当倍数调整以使其进入无符号整数范围,然后转换为无符号整数类型.
这些过程通常会产生不同的结果,差异为1.但是,测试它,它是Visual C++ 11.0和MinGW g ++ 4.7.1使用的第一个过程.我怀疑这是标准强制要求的(例如,C++ 11最终得到关于负数整数除法结果的明确规则):
#include <math.h>
#include <windows.h>
using namespace std;
#include <iostream>
DWORD test1()
{
double floatValue = -1.23456;
DWORD const dwValue = floatValue;
cout << dwValue << endl;
return dwValue;
}
DWORD test2()
{
double floatValue = -1.23456;
double reduced = floatValue + (1uLL << 32);
DWORD const dwValue = reduced;
cout << dwValue << endl;
return dwValue;
}
int main()
{
cout << DWORD(-1) << endl;
DWORD const t1 = test1(); cout << 1uLL + DWORD(-1) - t1 << endl;
DWORD const t2 = test2(); cout << 1uLL + DWORD(-1) - t2 << endl;
}
Run Code Online (Sandbox Code Playgroud)
输出,使用Visual C++ 11.0和MinGW g ++ 4.7.1:
4294967295 4294967295 1 4294967294 2
通常,转换(通过简单分配或初始化执行)会丢失数据.
编译器可能会对此发出警告.使其闭合的一种可能方式(可能或可能不起作用)是使用a static_cast来明确转换.无论如何,要注意转换必须在一般情况下丢失数据,因为通常浮点值比a更多位DWORD.
然而,有一种情况,其中a DWORD有足够的位,而且是类型的值float,在Windows中是32位IEEE.
因此,您可以将任何float值表示为DWORD具有相同位的值,但数值之间的连接看起来非常随意.它是否实际有用取决于您的其他应用.它有什么期望,或它能处理什么?
#include <windows.h>
#include <iostream>
using namespace std;
DWORD dwordBitsFrom( float const number )
{
return *reinterpret_cast< DWORD const* >( &number );
}
float floatFromBits( DWORD const bits )
{
return *reinterpret_cast< float const* >( &bits );
}
int main()
{
float const original = -1.23;
DWORD const bits = dwordBitsFrom( original );
float const reconstituted = floatFromBits( bits );
cout << original << endl;
cout << bits << endl;
cout << reconstituted << endl;
}
Run Code Online (Sandbox Code Playgroud)
输出,使用Visual C++ 11和g ++ 4.7.1(实际上任何实用的Windows C++编译器):
-1.23 3214766244 -1.23
但请注意,虽然后一种转换在Windows中定义良好,但C++标准不支持Windows规则.从严格的形式来看,不恰当地将上述代码视为与平台无关,以上打破了C++ 的严格别名规则.哪位g ++非常乐意通知您:
[D:\dev\test] > gnuc --strict-aliasing foo.cpp foo.cpp: In function 'DWORD dwordBitsFrom(float)': foo.cpp:7:55: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] foo.cpp: In function 'float floatFromBits(DWORD)': foo.cpp:12:53: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] [D:\dev\test] > _
为了让像g ++这样的愚蠢的编译器感到高兴,你必须通过字节缓冲区进行转换.这很烦人,因为警告是关于编译器检测到你所表达的内容,而不是它可能适用的一些非常不理想的边际优化.当它能够检测到它不应该时,为什么它不能不做那些不受欢迎的事情,而不是警告它无法做到这一点?或者,为什么它根本不能不做呢?既然没有人想要它.
但无论如何,这里的代码使g ++闭嘴:
#include <windows.h>
#include <iostream>
#include <string.h> // memcpy
using namespace std;
static_assert( sizeof( DWORD ) == sizeof( float ), "y DWORD no same size float?" );
int const nBytes = sizeof( DWORD );
DWORD dwordBitsFrom( float const number )
{
char buffer[nBytes];
DWORD result;
memcpy( buffer, &number, nBytes );
memcpy( &result, buffer, nBytes );
return result;
}
float floatFromBits( DWORD const bits )
{
char buffer[nBytes];
float result;
memcpy( buffer, &bits, nBytes );
memcpy( &result, buffer, nBytes );
return result;
}
int main()
{
float const original = -1.23;
DWORD const bits = dwordBitsFrom( original );
float const reconstituted = floatFromBits( bits );
cout << original << endl;
cout << bits << endl;
cout << reconstituted << endl;
}
Run Code Online (Sandbox Code Playgroud)
当然,由于代码更冗长,效率更低,人们可能会认为关闭一个愚蠢的编译器(即g ++)是不值得的.我个人认为这不值得.相反,只是说-fno-strict-aliasing对G ++,并且使用了reinterpret_cast,因为这是它的,为什么我们的语言有它.
总而言之,如果您的其他程序期望数值(如果可能)接近原始浮点值,则只需DWORD通过分配或初始化转换为可能使用a static_cast来抑制编译器警告.
如果你的其他程序需要一个值的位float,那么只需使用reinterpret_cast转换.上面的代码显示了如何使用效率更低,更详细和吸引bug的方法,memcpy而不仅仅是为了取悦g ++编译器.但我的建议是,如果这是相关的,那么只需通过-fno-strict-aliasing(另一个有用的选项,使g ++编译器与实用性-fwrapv保持一致)来抑制g ++警告,是,应该总是使用恕我直言.
| 归档时间: |
|
| 查看次数: |
4419 次 |
| 最近记录: |