【问题标题】:char* to double and back to char* again ( 64 bit application)char* 翻倍并再次返回 char*(64 位应用程序)
【发布时间】:2011-09-26 20:21:19
【问题描述】:

我正在尝试将 char* 转换为 double 并再次转换回 char*。如果您创建的应用程序是 32 位但不适用于 64 位应用程序,则以下代码可以正常工作。当您尝试从 int 转换回 char* 时会出现问题。例如,如果 hello = 0x000000013fcf7888 则转换为 0x000000003fcf7888 只有最后 32 位是正确的。

#include <iostream>
#include <stdlib.h>
#include <tchar.h>
using namespace std;


int _tmain(int argc, _TCHAR* argv[]){

    char* hello = "hello";
    unsigned int hello_to_int = (unsigned int)hello;
    double hello_to_double = (double)hello_to_int;

    cout<<hello<<endl;
    cout<<hello_to_int<<"\n"<<hello_to_double<<endl;

    unsigned int converted_int = (unsigned int)hello_to_double;
    char* converted = reinterpret_cast<char*>(converted_int);

    cout<<converted_int<<"\n"<<converted<<endl;

    getchar();
    return 0;
}

【问题讨论】:

  • 这些转换既无用又危险(仅将 指针 转换为浮点数的想法就让我感到畏缩)。你应该避开它们。
  • @user965772 你为什么要这样做?
  • 当你理解它时,铸造就足够危险了......
  • 尤其是 unsigned int convert_int = (unsigned int)hello_to_double;我认为是毁灭的秘诀。对于足够大的整数 int 来加倍到 int 不会以您开始的数字结尾(它与浮点运算有关)

标签: c++ visual-c++ win32ole


【解决方案1】:

在 64 位 Windows 指针是 64 位,而 int 是 32 位。这就是为什么您在投射时会丢失高 32 位数据的原因。代替int 使用long long 来保存中间结果。

char* hello = "hello";
unsigned long long hello_to_int = (unsigned long long)hello;

对反向转换进行类似的更改。但这并不能保证转换功能正确,因为双精度可以很容易地表示整个 32 位整数范围而不会损失精度,但对于 64 位整数则不然。

另外,这行不通

unsigned int converted_int = (unsigned int)hello_to_double;

这种转换只会截断浮点表示中小数点后的任何数字。即使将数据类型更改为unsigned long long,问题仍然存在。您需要reinterpret_cast&lt;unsigned long long&gt; 才能使其正常工作。

尽管如此,根据指针的值,您仍然可能会遇到麻烦。例如,转换为 double 可能会导致该值成为 signalling NaN,在这种情况下,您的代码可能会引发异常。

简单的答案是,除非您是为了好玩而尝试这样做,否则不要进行此类转换。

【讨论】:

    【解决方案2】:

    您不能在 64 位 Windows 上将 char* 强制转换为 int,因为 int 是 32 位,而 char* 是 64 位,因为它是一个指针。由于 double 始终是 64 位,因此您可以在 doublechar* 之间进行转换。

    【讨论】:

    • 不过,我认为他不会用“大”指针值来解决这个问题,因为 double 中只有 52 位保留用于尾数。
    • 可以char*转换成int。结果不一定是有意义的。
    【解决方案3】:

    如果它适用于任何系统、任何地方,只要你自己幸运并继续前进。将指针转换为整数是一回事(只要整数足够大,您就可以摆脱它),但是双精度数是浮点数 - 您所做的事情根本没有任何意义,因为double 不一定能够表示任何随机数。 double 有范围和精度限制,以及它如何表示事物的限制。它可以表示范围很广的数字,但不能表示该范围内的每个数字。

    请记住,双精度数有两个组成部分:尾数和指数。总之,这些允许您表示非常大或非常小的数字,但尾数的位数有限。如果尾数中的位用完,您将在尝试表示的数字中丢失一些位。

    显然你在某些情况下侥幸逃脱了它,但你要求它做一些它不是为它而设计的,而且它显然不适合的事情。

    只是不要那样做 - 它不应该工作。

    【讨论】:

      【解决方案4】:

      将任何整数(特别是位的集合)编码为浮点值的几个问题:

      1. 从 64 位整数到双精度数的转换可能是有损的。 double 具有 53-bits 的实际精度,因此 2^52 以上的整数(给或取一个额外的 2)不一定会精确表示。
      2. 如果您决定将指针的位重新解释为double(通过unionreinterpret_cast),如果您碰巧将指针编码为一组无效的位,您仍然会遇到问题双重代表。除非您可以保证 double 值永远不会被 FPU 写回,否则 FPU 可以静默地将无效双精度转换为另一个无效双精度(参见 NaN),即表示相同值但具有不同的双精度值位。 (See this for issues related to using floating point formats as bits.)

      您可以安全地以双精度编码 32 位指针,因为它肯定适合 53 位精度范围。

      【讨论】:

        【解决方案5】:

        只有最后 32 位是正确的。

        那是因为您平台中的int 只有 32 位长。请注意,reinterpret_cast 仅保证您可以将指针转换为足够大小的 int(不是您的情况),然后返回。

        【讨论】:

          【解决方案6】:

          这符合预期。

          通常char* 在 32 位系统上为 32 位,在 64 位系统上为 64 位; double 在两个系统上通常都是 64 位。 (这些尺寸是典型的,并且可能对 Windows 是正确的;该语言允许更多的变化。)

          据我所知,从指针到浮点类型的转换是未定义的。这不仅仅意味着转换的结果是不确定的;尝试执行这种转换的程序的行为是未定义的。如果运气好,程序会崩溃或无法编译。

          但是您要从指针转换为整数(这是允许的,但由实现定义),然后从整数转换为双精度(对于有意义的数值是允许且有意义的——但转换后的指针值不是有数字意义)。您正在丢失信息,因为并非双精度的所有 64 位都用于表示数字的大小;通常使用 11 位左右的位来表示指数。

          你所做的完全没有意义。

          您到底想完成什么?不管是什么,肯定有更好的方法来做到这一点。

          【讨论】:

            猜你喜欢
            • 2015-09-19
            • 2023-03-11
            • 2020-09-04
            • 1970-01-01
            • 2015-06-21
            • 2011-06-23
            • 2012-02-24
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多