2

C の構造体の整列されていないメンバーにアクセスしても問題ないかどうかをテストしたいので、コードを参照してください

#include <stdio.h>

#pragma pack(1)  /* force 1 byte alignment */

/* either member b or member d is mis-aligned */
typedef struct
{
    int b;
    unsigned char c;
    unsigned int d;
}A ;


int main(int argc, char *argv[])
{
    A _a = {0};
    unsigned int *p = NULL;
    unsigned int *q = NULL;


    printf("addr of _a : 0x%08x, size of _a : %u\n", &_a, sizeof(_a));

    p = (unsigned int*)(&_a.b);
    q = (unsigned int*)(&_a.d);

    /* should this fail ? */
    (*p)++ , (*q)++;

    return 0;

}

メモリ アクセスのミスアラインによる例外が原因でプログラムがクラッシュすると仮定しますが、Linux 3.6.11(GCC 4.7.2)、WinXP(MingW)、codepad オンライン コンパイラでテストした結果、非常にうまく機能することが判明しました。 ( http://codepad.org/yOoc8ACG )

結果を説明してください.OSがプログラムを保存するために何かをしたと思います.VxWorksや他のオペレーティングシステムで動作するかどうかはまだ疑問です.

注: コードは Intel ベースのマシンで実行されます!

前もって感謝します !

4

4 に答える 4

1

上記の回答のいくつかは、「x86 なので失敗しない」と言っていますが、これは完全には正しくありません。それを行う OS がないことは知っていますが、x86 プロセッサを構成して、ユーザーモードでアライメントされていないアクセスでエラーが発生するようにすることができます [カーネルモードではありませんが、投稿されたコードはユーザーモードコードのように見えます]。しかし、私が言ったように、実際にこのビットを構成する単一の OS を私は知りません。また、プロセッサがアライメントされていないメモリ アクセスに対してフォールトすることを予期していないコードが壊れる可能性が非常に高くなります。

どのように見ても、アライメントされていないアクセスの動作は定義されていないか、せいぜい実装によって定義されています。これは、そのような操作の結果が、「期待どおりに動作する」から「プログラムがクラッシュする」までの範囲に及ぶことを意味します。その範囲の中間には、おそらく「クラッシュしないが、期待どおりに動作しない」という最悪のオプションがあります。たとえば、直前に整列されたアドレスに対応する値を取得することがあります。 [下位メモリアドレス] フェッチする予定のデータ、またはフェッチは実際には正しく実行されますが、プロセッサがトラップしていくつかのステップで操作を実行し、その後、トラップ。複数のスレッドも実行している場合は、また、変数への更新がアトミックな方法で行われていないことに気付くかもしれません。そのため、「1 の半分、もう 1 の半分」の値が得られ、明らかに非常に奇妙な結果につながる可能性があります。これは、「少しうまくいかないが、すぐに明らかな方法ではない」という潜在的なシナリオの決定的なリストではありません.

私のアドバイスは次のとおりです。アライメントを台無しにしないでください。また、アライメントされていない要素にアクセスするコードを絶対に書かないように、絶対に最善を尽くしてください。それはおそらく戻ってきて、遅かれ早かれあなたを噛むでしょう...

于 2013-03-13T15:48:51.230 に答える
1

おそらく、Intel マシンで実行していると思われます。x86 アーキテクチャは、ミスアライン アクセスを問題なく処理できます。ただし、他のアーキテクチャでは問題が発生する可能性があります。アーキテクチャがたまたまミスアライン アクセスをサポートしていない場合でも、ある種の CPU 例外ハンドラでシングル バイト アクセスを使用してミスアライン アクセスをエミュレートすることで、オペレーティング システムがそれを回避できる場合があります。

テストプログラムでも必要だ(*p)++と思います。(*q)++

于 2013-03-13T15:08:17.430 に答える
0

結果は、アーキテクチャとカーネル構成によって異なります。通常、x86 では、位置合わせされていないデータにアクセスできますが、パフォーマンスが多少低下します。これは主に、古いファミリの CPU との互換性によるものです。

ARM および SPARC では、動作はカーネル構成によって異なります。このミスアライメント データ アクセスは、OS によって禁止、許可、またはエミュレートされる可能性があります。後者の場合、ハードウェア例外はカーネルによってインターセプトされ、一部の OS の平和なコードでエミュレートされます。

これは、コンパイラのバージョンが適切になると、より困難になります。たとえば、最新の GCC は、データが整列されていないことがわかった場合に、非アトミックな方法で (つまり、複数の命令を使用して) 整列されていないデータにアクセスできる特別なコードを生成します。

于 2013-03-13T15:21:55.223 に答える
0

x86 ベースのアーキテクチャは、そのワード アクセス命令がミスアラインされたアドレスで使用できるという点で珍しいものです。結果として得られる操作は遅く、アトミックではありませんが、機能します。

プログラムに が含まれるとすぐに、#pragmaその意味は (せいぜい) 実装定義になります。一般的に言えば、データ メンバーのアドレスをunsigned int*変数に割り当てると、実装はそれが正しく整列されていない可能性があることを「忘れる」ため、整列されていないロードのコードは発行されません。したがって、重要なアーキテクチャでは、どちら*p*q(または両方) が機能しません。

于 2013-03-13T15:12:21.680 に答える