将double转换为十六进制 - 代码审查

时间:2012-04-03 14:44:24

标签: c++ ieee-754

我有以下代码,它采用double值并将其转换为十六进制表示,反之亦然。我想知道它是否有任何潜在的问题 - 我是否忽略了一些东西。

double hex_to_double2(string &hexString)
{
    unsigned char byte_string[sizeof(double)];
    int number;

    int j = 0;

    for(int i = 0; i < hexString.size() ; i += 2)
    {
        sscanf(&hexString[i], "%02x", &number);
        byte_string[j] = (unsigned char)number;
        ++j;
    }

    double p = (double&)byte_string;
    return p;
}

std::string double_to_hex_string(double d)
{
    unsigned char *buffer = (unsigned char*)&d;
    int bufferSize = sizeof(double);

    char converted[bufferSize * 2];

    int j = 0;
    for(int i = 0 ; i < bufferSize ; ++i)
    {
        sprintf(&converted[j*2], "%02X", buffer[i]);
        ++j;
    }
    string hex_string(converted);
    return hex_string;
}

似乎工作正常。但有人告诉我char converted[bufferSize * 2];应该是char converted[bufferSize * 2 + 1];

是这样的吗?

6 个答案:

答案 0 :(得分:2)

是。每次调用sprintf()都会在缓冲区中写入三个字符:两个十六进制数字和一个null来终止字符串。最后一个将在当前实现的缓冲区之外写一个。

答案 1 :(得分:2)

是的,converted的大小应为bufferSize * 2 + 1。你需要在字符串末尾留出零或空字符的空间。

sprintf在字符串的末尾插入一个空字符,但是你没有为它腾出空间;这意味着它正在破坏缓冲区之后的内存中的某些值。很难预测这会产生什么副作用;它可能会破坏其他变量的值,它可能会使程序崩溃,或者它似乎可能正常工作。

答案 2 :(得分:1)

double放入char byte_string [sizeof(double)]的另一个问题是对齐。这个相当棘手的策略叫做 type punning 。您也希望在该函数中分配sizeof(double)*2个字节,然后在缓冲区的中间构造一个对齐的指针。

一般来说,这种“铸造”是一个坏主意,但你几乎就是在规则的右边。您只想将double转换为char数组,而不是相反。此外,scanf可以为您完成更多工作,并消除循环。

double hex_to_double2(string &hexString)
{
    double value;

    sscanf( hexString.c_str(), "%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
            (char*) & value, // note, this is a reinterpret_cast
            (char*) & value + 1,
            (char*) & value + 2,
            (char*) & value + 3,
            (char*) & value + 4,
            (char*) & value + 5,
            (char*) & value + 6,
            (char*) & value + 7 );

    return p;
}

您只能使用从POD类型(普通旧数据或C兼容)到char的这种指针类型转换。

我会反过来作为练习:)。

答案 3 :(得分:1)

这是我用来将两个单独的双精度数转换为十六进制(firstNumber和secondNumber)的非常简单的方法:

std::string hexCodes = "0123456789abcdef";

std::stringstream finalResult;

finalResult << hexCodes.at(floor(firstNumber/ 16)) << hexCodes.at(firstNumber- (16 * (floor(firstNumber/ 16))));

finalResult << hexCodes.at(floor(secondNumber/ 16)) << hexCodes.at(secondNumber- (16 * (floor(secondNumber/ 16))));

std::string finalString = finalResult.str();

我不是很擅长编写代码,在搜索谷歌搜索结果这个问题之后我没有找到任何解决方案,所以写了这个并且它有效......到目前为止

答案 4 :(得分:0)

是的,字符数组(也称为C字符串)通常应以'\ 0'结尾。这在C中用作长度指示器。

char converted[bufferSize * 2 + 1];
converted[bufferSize*2] = '\0';
or
std::memset(converted, 0, bufferSize*2+1);

答案 5 :(得分:0)

  

......任何潜在的问题......

hex_to_double2不检查byte_string缓冲区中的字符串是否适合:您应该提前检查hexString.size(),或者为for循环添加退出条件。

您还会返回一个指向本地缓冲区的指针,当hex_to_double2返回时,该指针超出范围 - 不要这样做。它可能会通过工作来欺骗你......直到它破裂。也许只返回std::vector<unsigned char> - 这会占用缓冲区生命周期,您可以使用push_back修复for循环。

  

有人char converted[bufferSize * 2]char converted[bufferSize * 2 + 1]

告诉我

是的,sprintf附加一个nul-terminator,因此输出缓冲区应该更大。但是,既然您仍在使用std::string,那么为什么不将十六进制数字格式化为std::ostringstream?同样,这将解决您的缓冲区大小问题并为您管理内存。