3

GNU GCC 4.7.0+では、いくつかの厳密なエイリアシング警告が表示されましたが、これを解決したいと思います。

私は(ハードウェアからの)ペイロードを持っています:

unsigned char payload[davidlt::PAYLOAD_SIZE];

私はこの行を持っていました:

*(uint32_t*)(payload + davidlt::DATA_OFFSET) = (pid & davidlt::PID_MASK) << davidlt::PID_SHIFT;

これにより、ペイロード内の特定の場所へのポインタが作成され、4バイトはとして解釈されuint32_tます。新しい値uint32_tタイプが計算され、ペイロードで置き換えられます。

私は得る:

warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

を使用して解決したいと思っていましたreinterpret_castが、同じ警告が表示されます。

*reinterpret_cast<uint32_t *>(payload + davidlt::DATA_OFFSET) = (pid & davidlt::PID_MASK) << davidlt::PID_SHIFT;

私が理解したように、許可されているcharまたはunsigned charに任意のデータを変換できますが、それは一方向にしか機能しません。

1つの解決策は、を作成することunionです。データへの異なるタイプの参照を作成する他の方法はありませんでしたunsigned charか?

ありがとう!デビッド

4

3 に答える 3

4

はい、データをcharまたはunsigned charとして表示することは許可されていますが、その逆は許可されていません。

この場合、代わりにmemcpyを使用する必要があります。あなたの行はpid値を取り、それをマスクし、それをシフトし、そしてそれをペイロードに挿入します。これを直接翻訳すると、次のようになります。

unsigned char payload[davidlt::PAYLOAD_SIZE];

uint32_t payload_pid = (pid & davidlt::PID_MASK) << davidlt::PID_SHIFT;

std::memcpy(payload + davidlt::DATA_OFFSET, &payload_pid, sizeof payload_pid);

もう1つの方法は、ペイロードを適切なサイズとメンバーを持つ標準のレイアウトタイプとして作成し、それをunsignedchar配列として表示することです。ペイロードの作成を制御していると仮定します。

struct Payload {
    ...
    uint32_t pid;
    ...
} payload;

payload.pid = (pid & davidlt::PID_MASK) << davidlt::PID_SHIFT;

static_assert(davidlt::PAYLOAD_SIZE == sizeof(Payload), "");

unsigned char (&payload_as_char)[davidlt::PAYLOAD_SIZE] = reinterpret_cast<unsigned char (&)[davidlt::PAYLOAD_SIZE]>(&payload);

これは、現在正しい方向に進んでいるため、厳密なエイリアシングルールに違反していません。

于 2012-07-01T16:55:51.873 に答える
1

ユニオンも未定義動作になります。この点でのみ使用できますchar-他のタイプは許可されていません。これには。が含まれますunsigned char

于 2012-07-01T14:48:13.977 に答える
1

あなたができることは、uint32_t代わりにの配列を作成することです。このようにして、次のようにアクセスできますが、次のようにuint32_tもアクセスできますunsigned char。これはエイリアシングルールに違反しません。

于 2012-07-01T15:04:39.073 に答える