4

本当に奇妙なことに気づきました。次の構造が定義されているとします

typedef struct
{
  uint32_t a;
  uint16_t b;
  uint32_t c;
} foo;

この構造は、ネットワークから受け取る大きなバッファに含まれています。

次のコードは x86 で動作しますがSIGBUS、ARM で受信します。

extern void * buffer;
foo my_foo;
my_foo = (( foo * ) buffer)[0];

ポインターの逆参照を memcpy に置き換えることで問題が解決しました。

ARM で SIGBUS について検索すると、これがメモリ アラインメントに関連していることがわかりました。

誰かが何が起こっているのか説明できますか?

4

4 に答える 4

5

あなたはそれを自分で言いました:あなたの特定のプロセッサにはメモリアラインメントの制限があり、そこbufferから1バイトを超える読み取りを許可するように正しくアラインされていません. 割り当ては、おそらくより大きなエンティティの 3 つの移動にコンパイルされます。

ではmemcpy()、アラインメントの制限はなく、任意の 2 つのアドレス間でコピーできる必要があるため、それを実装するために必要なことは何でも行いますおそらく、アドレスが揃うまでバイトごとにコピーするのが一般的なパターンです。

余談ですが、配列のインデックスを使用せずにコードを記述した方が明確です。

extern const void *buffer;
const foo my_foo = *(const foo *) buffer;
于 2013-10-01T11:09:26.283 に答える
3

C 標準 [ISO/IEC 9899:2011] - 6.3.2.3、パラグラフ 7:

オブジェクトまたは不完全な型へのポインターは、別のオブジェクトまたは不完全な型へのポインターに変換される場合があります。結果のポインターがポイント先の型に対して正しく配置されていない場合、動作は未定義です。

出典: CERT セキュア コーディング標準

于 2013-10-01T11:22:37.220 に答える
1

ARM ベースのシステムは、構造体がワード境界に整列することを想定しています。そうでない場合は、さまざまな動作を行うことができます (たとえば、Linux カーネルでは、これらの動作は で説明されて/proc/cpu/alignementおり、そのうちの 1 つは SIGBUS を送信することです)。

あなたがしたmemcpy()ことは、データ構造のアライメントを強制したことです。

于 2013-10-01T11:25:52.183 に答える
0

私はしばらく前にフリースケールimxでダウンロードアプリケーションを開発していました....そこでメモリアライメントの問題がありました(実行可能ファイルが512バイトの倍数であることが要件でした)...armとx86の根本的な違い...しかし、 memcpy で覚えておいてほしいのは、1 バイトごとにコピーを行うということです ...だから、うまくいくかもしれませんが、実行時の問題を必ずチェックしてください...特定のプラットフォームに合わせた構造。

于 2013-10-01T11:46:07.863 に答える