1

编辑:跳到我最新版本的问题的水平规则下方。

仅假设 sizeof(double) * CHAR_BITS <= 64,C++03 保证以下程序中的断言始终得到满足?

union u {
  std::int64_t m_int;
  double       m_double;
};

int main()
{
  double d = get_a_random_double();

  u u1;
  u1.m_double = d;

  u u2;
  u2.m_int = u1.m_int;

  assert(u2.m_double == d);
}

我担心标准可能无法保证 int64_t 值的副本保留我们用来保存双精度的所有位。

另一方面,我很确定标准保证以下使用 chars 而不是 unt64_t 的替代方案始终满足断言:

struct chars {
  char m_x[sizeof(double)];
};

union u {
  chars  m_chars;
  double m_double;
};

int main()
{
  double d = get_a_random_double();

  u u1;
  u1.m_double = d;

  u u2;
  u2.m_chars = u1.m_chars;

  assert(u2.m_double == d);
}

你同意?


编辑:

好的,我必须承认标准不支持通过联合进行的转换。

那么这个我尝试在不使用联合的情况下通过一系列字符传输双精度数的情况呢:

int main()
{
  double d, e;
  char c[sizeof(double)];

  char* p_d = static_cast<char*>(static_cast<void*>(&d));
  char* p_e = static_cast<char*>(static_cast<void*>(&e));

  d = get_a_random_double();

  // double -> chars
  std::copy(p_d, p_d+sizeof(double), c);

  // chars -> double
  std::copy(c, c+sizeof(double), p_e);

  assert(e == d);
}

这个标准是否保证始终满足断言?

编辑:是的!参见 C++11 3.9/2“类型”

下一个我尝试在不使用联合的情况下通过 int64_t 传输双槽的情况如何。

我知道 int64_t 不是 c++03 的一部分,所以让我们来谈谈 c++11。

再次注意,我假设 sizeof(double) * CHAR_BITS <= 64。

int main()
{
  double d, e;
  std::int64_t i, j;
  char c[sizeof(std::int64_t)];

  char* p_d = static_cast<char*>(static_cast<void*>(&d));
  char* p_e = static_cast<char*>(static_cast<void*>(&e));
  char* p_i = static_cast<char*>(static_cast<void*>(&i));
  char* p_j = static_cast<char*>(static_cast<void*>(&j));

  d = get_a_random_double();

  // double -> chars -> std::int64_t
  std::copy(p_d, p_d+sizeof(double), c);
  std::copy(c, c+sizeof(std::int64_t), p_i);

  // std::int64_t -> std::int64_t
  j = i; // <------------ Are all bits preserved here?

  // std::int64_t -> chars -> double
  std::copy(p_j, p_j+sizeof(std::int64_t), c);
  std::copy(c, c+sizeof(double), p_e);

  assert(e == d);
}

和以前一样,我担心的一个问题是复制标准整数类型之一 (std::int64_t) 是否会“损坏”某些位(例如,一些不参与整数值表示的位)。或者,整数分配是否保证总是忠实地复制整数占用的字节的所有位?

4

3 回答 3

4

不,实际上这是未定义的行为:

u u1;
u1.m_double = d;

u u2;
u2.m_int = u1.m_int;

你不能设置u1.m_double和阅读u1.m_int

一次只允许一名活跃的工会成员。

于 2013-01-28T16:15:37.823 回答
4

该语言本身并不能保证您可以使用除charunsigned char指针之外的任何其他类型来访问其他数据类型——即使这样也是相当有限的。

这完全取决于您希望代码的可移植性。有些机器处理浮点数的方法很奇怪,并且将它们四处转换会做坏事。

在实践中,大多数处理器对您刚刚完成的操作非常满意,并且大多数编译器都非常乐意生成“正确”代码以覆盖 64 位整数和 64 位浮点数,并将其传输到方式。

当您尝试在 DSP、旧的 IBM 硬件、Cray YMP 或其他有点不寻常的东西上运行它时,麻烦就来了。或者,如果您开始使用未经测试的编译器。

So to some degree, it comes down to "how portable do you need it to be", and how well is your software tested for this to not creep through as a strange error that only occurs on Tuesdays in months with R in the name, and only on days that are evenly divisible with 7 and 3, with a full moon? [And inevitably, only by your most important customer that is in a country about 12 hours off your timezone].

于 2013-01-28T16:24:22.030 回答
1

所有具有固定大小的类型都是 c++11。在此之前,该标准只定义了变量必须保持的最小位数(其中大多数只保证至少与前一个实际一样大......)。所以std::int64_t将在 c++03 中未定义,您不能依赖任何大小的其他整数(包括 char!)。


此外,正如 Luchian Grigore 指出的那样:(任何)标准都没有定义给一个工会成员写信和从另一个工会成员读。然而,虽然不能保证您编写的代码能够正常工作,但大多数编译器会按照您的预期方式解释它。

于 2013-01-28T16:17:11.247 回答