0

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

首先...可以将带符号的 DWORD 解释为无符号的 DWORD ..?

还...如何将带符号的浮点数转换为 DWORD(带符号)..?

4

1 回答 1

7

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

首先...可以将带符号的 DWORD 解释为无符号的 DWORD ..?

还...如何将带符号的浮点数转换为 DWORD(带符号)..?

DWORD是由 Windows API 定义的 32 位无符号整数类型。没有“签名的 DWORD”之类的东西。可能您的意思是相应的签名类型。

在 C++ 中,所有浮点类型(floatdoublelong double都是有符号类型,因此谈论“有符号浮点”是不寻常的。大概你的意思是它可以是一个负值。将负浮点值转换为无符号整数有两种主要可能性:

  • 就好像浮点值,比如说-1.23,被转换为有符号整数,然后通过 2 n的适当倍数进行调整,使其进入无符号整数范围,或者

  • 就好像浮点值,再次说,通过 2 n-1.23的适当倍数调整,使其进入无符号整数范围,然后转换为无符号整数类型。

这些过程通常会产生不同的结果,相差 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;
}

输出,使用 Visual C++ 11.0 和 MinGW g++ 4.7.1:

4294967295
4294967295
1
4294967294
2

通常,转换(通过简单的赋值或初始化执行)会丢失数据。

编译器可能会对此发出警告。使其关闭的一种可能方法(可能有效也可能无效)是使用 astatic_cast使转换显式。无论如何,请注意在一般情况下转换必须丢失数据,因为通常浮点值比DWORD.

然而,在一种情况下, aDWORD有足够的位,这是一个 type 的值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;
}

输出,使用 Visual C++ 11 和 g++ 4.7.1(以及任何实际有用的 Windows C++ 编译器):

-1.23
3214766244
-1.23

但是请注意,虽然后一种转换在 Windows 中得到了很好的定义,但 C++ 标准不支持 Windows 规则。从严格的形式上看,不恰当地将上述代码视为平台无关,这违反了C++严格的别名规则。哪个 g++ 很高兴通知您:

[D:\开发\测试]
> gnuc --strict-aliasing foo.cpp
foo.cpp:在函数“DWORD dwordBitsFrom(float)”中:
foo.cpp:7:55: 警告:取消引用类型双关指针将破坏严格别名规则 [-Wstrict-aliasing]
foo.cpp:在函数'float floatFromBits(DWORD)'中:
foo.cpp:12:53:警告:取消引用类型双关指针将破坏严格别名规则 [-Wstrict-aliasing]

[D:\开发\测试]
> _

为了让 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;
}

当然,由于它是更冗长且效率更低的代码,人们可能会认为关闭一个愚蠢的编译器(即 g++)是不值得的。个人认为值得。相反,只需-fno-strict-aliasing对 g++ 说,并使用reinterpret_cast, 因为这就是它的用途,为什么我们在语言中使用它。

总而言之,如果您的其他程序需要一个尽可能接近原始浮点值的数值,那么只需通过分配或初始化转换为DWORD可能使用 astatic_cast来抑制编译器警告。

如果您的其他程序需要一个值的float,那么只需使用reinterpret_cast转换。上面的代码展示了如何使用更低效、更冗长和更容易吸引错误的代码memcpy来取悦 g++ 编译器。但我的建议是,如果这是相关的,那么只需通过-fno-strict-aliasing(另一个使 g++ 编译器符合实用性的有用的此类选项是-fwrapv,恕我直言,应该始终使用它)来抑制 g++ 警告。

于 2012-11-18T03:10:58.187 回答