【问题标题】:Converting from double to hexadecimal back to double using union使用联合从双精度转换为十六进制返回双精度
【发布时间】:2017-10-10 14:03:13
【问题描述】:

我什至不确定我的标题是否准确,但对于我的项目,我需要取一个双精度并将其转换为十六进制,然后再将其转换回双精度。但为了做到这一点,我认为我需要重载运算符 有人可以指出我应该如何重载

#include <iostream>
#include <iomanip>
#include <cstdint>

using namespace std;

void out_char_as_hex(int c)
{
    cout << hex << setw(2) << setfill('0') << c;
}


int main()
{
    union { double d; uint64_t u; } tmp;
    double x = -0.15625;
    tmp.d = x;

    cout << out_char_as_hex(tmp.d) << endl;

    return 0;
}

如果有帮助,这是一个问题“如果 x 是 double 类型的变量,它的二进制表示可以重新解释为 64 位整数,可以精确表示。为此,您可以获取内存地址到 double 类型的变量并重新解释将其转换为 64 位 int 指针或使用联合。为了使文本表示更紧凑,我们使用基数 16(十六进制)。例如,应保存双精度数 -0.15625归档为 16 个字符的序列 bfc4000000000000(参见 DemoHex.cpp 中的示例, 使用联合)。读取时需要读取整数 以十六进制格式保存并将其重新解释为双精度。 您需要修改 operator>"

【问题讨论】:

  • 你“不能”使用联合。在 C++ 中通过联合进行类型双关是非法的。
  • 也许我遗漏了一些东西,但这个问题对我来说没有意义。浮点值没有十六进制表示。你能写一些预期的输入/输出吗?
  • 如果您放弃“使用联合”要求,则可以通过使用 memcpy 使其在没有未定义行为的情况下工作。
  • 我不认为这是基本的 C++,尽管在 C 时代,人们希望尽快使用这些技巧。 Primitives/std::string/iostream/main、loop/branch、class/function、containers (std::vector)、头文件/源文件。迭代器/算法/lambdas,继承/多态,其次是基本模板,转换和字节表示真正属于之后。
  • 看来你的教授对 C++ 的了解还不够,无法教授它。不幸的是,这也不例外,这是常态。如果你真的想学习 C++,请带着很大的怀疑态度和read a book 来学习你在那里学到的一切。

标签: c++ operator-overloading


【解决方案1】:

这是一个不使用联合的版本,而是将位模式从double 复制到uint64_t

假设此位模式对整数有效,则复制也应该有效。它还产生了预期的输出。

#include <iostream>
#include <iomanip>
#include <cstdint>

using namespace std;

void out_char_as_hex(std::uint64_t c)
{
    cout << hex << setw(16) << setfill('0') << c << endl;
}


int main()
{
    uint64_t u;
    double x = -0.15625;

    std::memcpy(&u, &x, sizeof(u));

    out_char_as_hex(u);

    return 0;
}

但是,这不是教授要求的解决方案,因此可能是“错误的”。

【讨论】:

  • 我从未听说过整数的无效位模式,而且我知道从 0x0000... 到 0xFFFF... 的每个模式;)。介意解释吗?还是您的意思是不适合给定整数的模式?
  • @Bo Persson 感谢您的帮助!但我认为我无法使用您的解决方案
  • @stefaanv - 曾经有一些奇怪的机器,其中不是 每个 位模式都是有效值。一些无效值可能会产生陷阱。不过,这些机器都不太可能有uint64_t 类型。 (只是想抢占 cmets 此处可能存在的未定义行为。)
  • 很高兴知道。我从未有过与这些一起工作的“乐趣”。对我来说是 8 位、2 的补码 CPU 的严格倍数,即使是 DSP 也是如此。
【解决方案2】:

如果转换只是为了打印,那么你不需要重载任何运算符。使用 io manipulator 'std::hexfloat' 您可以以十六进制打印浮点数。

根据您的示例代码和解释,我认为您正在尝试执行以下操作

#include <iostream>
#include <iomanip>

union test
{
    double x;
    uint64_t y;
};

// Insertion operator is overloaded to take union and 
// print uint64_t value from it.  
std::ostream & operator << (std::ostream &out, const test &t)
{
    out << std::hex << std::setw(50) << std::setfill('0') << t.y;
    return out;
}

int main()
{
    test t;
    t.x = -0.15625;
    std::cout << t << std::endl;    
    return 0;
}

这里打印的是一个位模式,用于在内存中存储浮点数(符号位、指数和尾数)。

更新: 上面的代码将导致未定义的行为,因为我们没有从最近写入的成员中读取(参考:http://en.cppreference.com/w/cpp/language/union

这是不使用联合的另一种方法。

#include <iostream>
#include <iomanip>

struct test
{
    double x;
};

std::ostream & operator << (std::ostream &out, test &t)
{
    uint64_t *y = reinterpret_cast<uint64_t *>(&t.x);
    out << std::hex << std::setw(50) << std::setfill('0') << *y;
    return out;
}

int main()
{
    test t;
    t.x = -0.15625;
    std::cout << t << std::endl;
    return 0;
}

【讨论】:

  • 您好 Nyemul,感谢您的帮助!这似乎是我需要的东西。我会努力消化的!澄清一下,这意味着如果只需要打印,则不需要“
  • 您不需要重载插入 (
  • 此答案与之前已删除的答案共享一个问题。您正在写信给工会的一名成员,然后从另一名成员那里阅读。在 C 中,这是很好定义的,但在 C++ 中,它是正式未定义的。从en.cppreference.com/w/cpp/language/union " 从最近未编写的联合成员中读取是未定义的行为。许多编译器作为非标准语言扩展实现了读取联合的非活动成员的能力。 所以它可能有效,但不是标准的。这也是我写非工会答案的原因。
  • BoPersson 感谢您的指点。但这意味着我们不能像在 C 中那样在 C++ 中使用联合。@Bert 谨慎使用上述建议
  • 大家好,非常感谢大家的帮助!它至少帮助我开始理解并朝着项目的正确方向努力。干杯!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-07
  • 1970-01-01
  • 2014-05-05
  • 2011-04-03
  • 1970-01-01
相关资源
最近更新 更多