3

最近、厳密なエイリアシングについてよく読んでいます。aC/C++ 標準では、次のコードは無効であると述べられています(未定義の動作が正しい) b

float *a;
...
int *b = reinterpret_cast<int*>(a);
*b = 1;

標準では、char*何でもエイリアスできると述べているため、char*変数への書き込みアクセスが行われるたびに、コンパイラーはキャッシュされたすべての値をリロードします。したがって、次のコードは正しいでしょう。

float *a;
...
char *b = reinterpret_cast<char*>(a);
*b = 1;

しかし、ポインターがまったく関与していない場合はどうでしょうか? たとえば、次のコードがあり、GCC は厳密なエイリアシングに関する警告をスローします。

float a = 2.4;
int32_t b = reinterpret_cast<int&>(a);

私がやりたいのは、の生の値をコピーaすることだけなので、厳密なエイリアシングは適用されません。ここに問題がある可能性がありますか、それとも GCC がそれについて過度に用心深いだけですか?

編集

memcpyを使用した解決策があることは知っていますが、コードが読みにくくなるため、その解決策を使用したくありません。

EDIT2

int32_t b = *reinterpret_cast<int*>(&a);も機能しません。

解決した

これはGCC のバグのようです。

4

3 に答える 3

3

一部のメモリをコピーしたい場合は、コンパイラにそれを行うように指示できます。

編集:より読みやすいコードのための機能を追加しました:

#include <iostream>
using std::cout; using std::endl;
#include <string.h>

template <class T, class U>
T memcpy(const U& source)
{
    T temp;
    memcpy(&temp, &source, sizeof(temp));
    return temp;
}

int main()
{
    float f = 4.2;
    cout << "f: " << f << endl;

    int i = memcpy<int>(f);
    cout << "i: " << i << endl;
}

[コード] [更新コード]

編集: ユーザー/GMan がコメントで正しく指摘したように、フル機能の実装では、TUPODであることを確認できます。ただし、関数の名前がまだmemcpyであることを考えると、元の と同じ制約を持つものとして扱う開発者に頼っても問題ないかもしれませんmemcpy。それはあなたの組織次第です。また、ソースではなく、宛先のサイズを使用してください。(ありがとう、オリ。)

于 2011-02-20T20:27:26.830 に答える
1

基本的に厳密なエイリアス規則は、「文字の配列を除いて、宣言されたものとは別の型でメモリにアクセスすることは未定義です」です。したがって、gcc は慎重すぎません。

于 2011-02-20T20:28:03.977 に答える
0

これが頻繁に行う必要がある場合は、ユニオンを使用することもできます。これは、この特定の目的のためにキャストや memcpy よりも読みやすいです。

union floatIntUnion {
  float a;
  int32_t b;
};

int main() {
  floatIntUnion fiu;
  fiu.a = 2.4;
  int32_t &x = fiu.b;
  cout << x << endl;
}

これは厳密なエイリアシングに関するあなたの質問に実際には答えていないことを認識していますが、この方法によりコードがきれいに見え、意図をよりよく示すことができると思います.

また、コピーを正しく行ったとしても、int取得した結果が他のプラットフォームでも同じfloatになるという保証はないので、クロスを作成する予定がある場合は、これらの float/int のネットワーク/ファイル I/O をカウントしてください。 -プラットフォーム プロジェクト。

于 2011-02-20T20:43:08.663 に答える