1. ホーム
  2. c

[解決済み] 型依存のポインタの再参照がストリクトエイリアスを破壊する問題の修正

2022-02-25 08:24:45

質問

GCCを使用して特定のプログラムをコンパイルする際、2つの警告を修正しようとしています。 警告は次のとおりです。

警告: 型打ちされたポインタの再参照は ストリクトエイリアスのルール [-Wstrict-aliasing] に従います。

で、犯人はこの2つです。

unsigned int received_size = ntohl (*((unsigned int*)dcc->incoming_buf));

そして

*((unsigned int*)dcc->outgoing_buf) = htonl (dcc->file_confirm_offset);

着信バッファー アウトゴーイング_バフ は以下のように定義されています。

char                    incoming_buf[LIBIRC_DCC_BUFFER_SIZE];

char                    outgoing_buf[LIBIRC_DCC_BUFFER_SIZE];

これは、私が調べてきたその警告の他の例とは微妙に違うようです。 ストリクト・エイリアシング・チェックを無効にするのではなく、問題を修正することを希望します。

ユニオンを使うという提案はたくさんありますが、このケースに適したユニオンは何でしょうか?

どのように解決するのですか?

まず最初に、エイリアシング違反の警告が出る原因を調べてみましょう。

エイリアシングルール は、単にオブジェクト自身の型、符号付き/符号なしバリアント型、または文字型( char , signed char , unsigned char ).

C言語では、エイリアシングのルールに違反すると未定義の動作が呼び出されます ( ということで、don't! ).

あなたのプログラムのこの行で。

unsigned int received_size = ntohl (*((unsigned int*)dcc->incoming_buf));

の要素がありますが incoming_buf 配列の型は char としてアクセスすることになります。 unsigned int . 確かに、式中のデリファレンス演算子の結果は *((unsigned int*)dcc->incoming_buf)unsigned int 型になります。

の要素にアクセスする権利しかないので、これはエイリアスルールに違反しています。 incoming_buf を通して配列することができます (上記のルールの概要を参照してください!) char , signed char または unsigned char .

2番目の原因でもまったく同じエイリアシングの問題があることに注意してください。

*((unsigned int*)dcc->outgoing_buf) = htonl (dcc->file_confirm_offset);

にアクセスします。 char の要素で構成されています。 outgoing_buf を通して unsigned int ということで、エイリアス違反になります。

解決策案

この問題を解決するには、配列の要素をアクセスしたい型に直接定義するようにすればよいでしょう。

unsigned int incoming_buf[LIBIRC_DCC_BUFFER_SIZE / sizeof (unsigned int)];
unsigned int outgoing_buf[LIBIRC_DCC_BUFFER_SIZE / sizeof (unsigned int)];

(ちなみに unsigned int は実装で定義されているので uint32_t を想定している場合は unsigned int は32ビット)。

この方法では unsigned int を使用して要素にアクセスすることで、 エイリアスルールに違反することなく配列にオブジェクトを追加できます。 char を、このようにします。

*((char *) outgoing_buf) =  expr_of_type_char;

または

char_lvalue = *((char *) incoming_buf);


EDITです。

特に、なぜプログラムがコンパイラからエイリアシングの警告を受けるのかを説明しています。