3

エンディアンネスについて読んで、スクワットを理解しました...

だから私はこれを書いた

main()
{
    int k = 0xA5B9BF9F;

    BYTE *b = (BYTE*)&k;    //value at *b is 9f
    b++;    //value at *b is BF
    b++;    //value at *b is B9
    b++;    //value at *b is A5
}

kに等しかったA5 B9 BF 9F

および (byte)pointer " walk " o/p は9F BF b9 A5

バイトが逆に保存されていることがわかりました...わかりました。

だから今、ビットレベルでどのように保存されているかを考えました...

「9f」(1001 1111) は「f9」(1111 1001) として保存されているということですか?

だから私はこれを書いた

int _tmain(int argc, _TCHAR* argv[])
{
    int k = 0xA5B9BF9F;
    void *ptr = &k;
    bool temp= TRUE;
    cout<<"ready or not here I come \n"<<endl;

    for(int i=0;i<32;i++)
    {   
        temp = *( (bool*)ptr + i );
        if( temp )
            cout<<"1 ";
        if( !temp)
            cout<<"0 ";
        if(i==7||i==15||i==23)
            cout<<" - ";
   }
}

ランダムな出力が得られます

いいえでも。「32」のように、私は賢明なことは何も得られません。

なぜ ?

4

5 に答える 5

7

完全を期すために、マシンはバイト順とビット順 の両方で記述されています。

intel x86 は、メモリ アドレスが増加するにつれてマルチバイト値を LSB から MSB の順に格納するため、Consistent Little Endian と呼ばれます。そのビット番号付け規則は、b0 = 2^0 および b31 = 2^31 です。

Motorola 68000 は、メモリ アドレスが増加するにつれてマルチバイト値を MSB から LSB の順に格納するため、不整合なビッグ エンディアンと呼ばれます。そのビット番号付け規則は、b0 = 2^0 および b31 = 2^31 です (Intel と同じです。これが、「一貫性のない」ビッグ エンディアンと呼ばれる理由です)。

32 ビットの IBM/Motorola PowerPC は、メモリ アドレスが増加するにつれてマルチバイト値を MSB から LSB の順に格納するため、コンシステント ビッグ エンディアンと呼ばれます。そのビット番号付け規則は、b0 = 2^31 および b31 = 2^0 です。

通常の高級言語の使用では、ビット順序は通常、開発者に対して透過的です。アセンブリ言語で記述したり、ハードウェアで作業したりする場合、ビット番号付けが機能します。

于 2010-05-28T21:47:20.107 に答える
5

Endiannessは、実験で発見したように、バイトがオブジェクトに格納される順序を指します。

ビットは異なる方法で格納されることはなく、常に 8 ビットであり、常に「人間が読める」(高→低)。

これで、コードは必要ないことを説明しました... コードについて:

for(int i=0;i<32;i++)
{   
  temp = *( (bool*)ptr + i );
  ...
}

これは、あなたが思っていることをしていません。ワードのビット数である 0 ~ 32 を繰り返し処理しています。しかし、あなたのtemp割り当てはすべて間違っています:)

bool*a は aと同じサイズであるint*ことに注意することが重要BigStruct*です。同じマシン上のすべてのポインターは同じサイズ (32 ビット マシンでは 32 ビット、64 ビット マシンでは 64 ビット) です。

ptr + iiアドレスにバイトを追加していptrます。の場合i>3、まったく新しい単語を読んでいます...これはセグメンテーション違反を引き起こす可能性があります。

使いたいのはbit-masksです。このようなものが動作するはずです:

for (int i = 0; i < 32; i++) {
  unsigned int mask = 1 << i;
  bool bit_is_one = static_cast<unsigned int>(ptr) & mask;
  ...
}
于 2010-05-28T20:57:20.860 に答える
3

バイトエンディアン

異なるマシンでは、このコードは異なる結果をもたらす可能性があります。

union endian_example {
   unsigned long u;
   unsigned char a[sizeof(unsigned long)];
} x;

x.u = 0x0a0b0c0d;

int i;
for (i = 0; i< sizeof(unsigned long); i++) {
    printf("%u\n", (unsigned)x.a[i]);
}

これは、さまざまなマシンが任意のバイト順序で値を自由に格納できるためです。これはかなり恣意的です。物事の壮大な計画には、後方または前方はありません。

ビットエンディアン

通常、ビットエンディアンについて心配する必要はありません。個々のビットにアクセスする最も一般的な方法は、シフト(>><<)を使用することですが、これらは実際にはバイトやビットではなく値に関連付けられています。それらは、値に対して算術演算を実行します。その値はビット(バイト単位)で格納されます。

Cでビットエンディアンの問題が発生する可能性があるのは、ビットフィールドを使用したことがある場合です。これはめったに使用されない(この理由と他のいくつかの理由で)Cの「機能」であり、aのメンバーstructが使用するビット数をコンパイラーに通知できます。

struct thing {
     unsigned y:1; // y will be one bit and can have the values 0 and 1
     signed z:1; // z can only have the values 0 and -1
     unsigned a:2; // a can be 0, 1, 2, or 3
     unsigned b:4; // b is just here to take up the rest of the a byte
};

この場合、ビットエンディアンはコンパイラに依存します。?yの最上位ビットまたは最下位ビットである必要がありthingます。知るか?ビットの順序(IPv4パケットヘッダーのレイアウト、デバイスの制御レジスタ、またはファイル内のストレージ形式などを記述する)が気になる場合は、別のコンパイラがこれを間違って実行することを心配したくないでしょう。仕方。また、コンパイラーは、ビットフィールドをどのように処理するかについて常に賢明であるとは限りません。

于 2010-05-28T22:21:04.717 に答える
3

あなたのマシンはほぼ確実にメモリの個々のビットをアドレス指定できないため、バイト内のビットのレイアウトは無意味です。エンディアンとは、マルチバイト オブジェクト内のバイトの順序のみを指します。

2 番目のプログラムを意味のあるものにするには (意味のある結果が得られないため、特に理由はありませんが)、特に&このアプリケーションでは、ビット単位の演算子について学ぶ必要があります。

于 2010-05-28T20:40:18.130 に答える
2

この行は次のとおりです。

temp = *( (bool*)ptr + i );

... このようなポインター演算を行うと、コンパイラーは、ポインターを、あなたが指しているもののサイズに加算した数だけ移動します。void* を bool* にキャストしているため、コンパイラはポインタを 1 つの「bool」のサイズだけ移動します。これはおそらくカバーの下の単なる int であるため、さらにメモリを出力します。思ったより。

バイト内の個々のビットをアドレス指定することはできないため、それらがどのように格納されているかを尋ねることはほとんど意味がありません. (あなたのマシンは、好きな方法でそれらを保存できますが、あなたにはわかりません)。気にするのは、実際にビットを 1 つずつ吐き出さなければならない I2C や RS232 などの物理インターフェイスを介して実際にビットを吐き出すときだけです。それでも、プロトコルはビットを吐き出す順序を定義し、デバイスドライバーコードは「値0xAABBCCDDのint」と「ビットシーケンス11100011の間で変換する必要があります... [何でも]プロトコルの順序で"。

于 2010-05-28T20:49:27.223 に答える