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 値のコピーが double を保持するために使用するすべてのビットを保持することが標準で保証されていないのではないかと心配しています。

一方、unt64_t の代わりに chars を使用する次の代替案は、常に assert を満たすことが標準によって保証されていると確信しています。

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);
}

同意しますか?


編集:

わかりました、ユニオンによる変換が標準でサポートされていないことを認めなければなりません。

では、ユニオンを使用せずに一連の文字を介して double を転送しようとする次の例はどうでしょうか。

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);
}

前と同じように、私の懸念の 1 つは、標準の整数型 (std::int64_t) の 1 つをコピーすると、一部のビット (たとえば、整数値表現に関与していない一部のビット) が「破損」する可能性があるかどうかです。または、整数の割り当ては、整数が占めるバイトのすべてのビットを常に忠実にコピーすることが保証されていますか?

4

3 に答える 3

4

いいえ、実際には未定義の動作です:

u u1;
u1.m_double = d;

u u2;
u2.m_int = u1.m_int;

u1.m_doubleを設定して読み取ることはできませんu1.m_int

一度にアクティブな組合員は 1 人だけです。

于 2013-01-28T16:15:37.823 に答える
4

char言語自体は、またはunsigned charポインター以外の型を使用して他のデータ型にアクセスできることを保証しません。それもかなり制限されています。

それはすべて、コードの移植性をどの程度にしたいかによって異なります。一部のマシンでは、浮動小数点数を処理する奇妙な方法があり、それらをキャストすると悪い結果が生じます。

実際には、MOST プロセッサはあなたが行ったことで完全に問題なく、ほとんどのコンパイラは、64 ビット整数を 64 ビット浮動小数点数でオーバーレイし、それを転送する「正しい」コードを完全に喜んで生成します。仕方。

問題は、これを DSP、古い IBM ハードウェア、Cray YMP、または少し変わったもので実行しようとすると発生します。または、非常にテストされていないコンパイラを使い始めた場合。

したがって、ある程度、それは「移植性が必要か」に帰着し、名前にRが含まれる月の火曜日にのみ発生する奇妙なエラーとして忍び寄らないように、ソフトウェアがどれだけうまくテストされているかということになります。 7と3で割り切れる満月の日だけ?[そして必然的に、タイムゾーンが約 12 時間ずれている国にいる最も重要な顧客によってのみ].

于 2013-01-28T16:24:22.030 に答える
1

固定サイズの型はすべて c++11 です。それ以前は、標準は変数が保持する必要があるビットの最小数のみを定義していました (それらのほとんどは、実際には少なくとも前のものと同じ大きさであることを保証するだけです...)。そのためstd::int64_t、c++03 では未定義になり、他の int (char を含む!) のサイズに依存することはできません。


また、Luchian Grigore が指摘するように、あるユニオン メンバーへの書き込みと別のユニオン メンバーからの読み取りは、(任意の) 標準によって定義されていません。それでも、作成したコードが機能するという保証はありませんが、ほとんどのコンパイラは意図したとおりに解釈します。

于 2013-01-28T16:17:11.247 に答える