已签名的浮点变量转换为无符号DWORD

P. *_*ery 0 c++ winapi

我试图将带符号的浮点变量转换为DWORD ... DWORD将被另一个程序使用,因此DWORD变量类型很重要...

首先......签名的DWORD可以解释为无符号的DWORD ..?

还...我怎样才能将签名的浮点数转换为DWORD(签名)..?

Che*_*Alf 6

我试图将带符号的浮点变量转换为DWORD ... DWORD将被另一个程序使用,因此DWORD变量类型很重要...

首先......签名的DWORD可以解释为无符号的DWORD ..?

还...我怎样才能将签名的浮点数转换为DWORD(签名)..?

DWORD是Windows API定义的32位无符号整数类型.没有"签名的DWORD"这样的东西.可能你的意思是相应的签名类型.

在C++中所有浮点类型(float,doublelong 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 ++警告,是,应该总是使用恕我直言.