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

和(字节)指针“ walk ” o/p 是9F BF b9 A5

所以我知道字节是向后存储的......好的。

~

所以现在我想它是如何存储在 BIT 级别的......

我的意思是“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 被称为 Consistent Little Endian,因为随着内存地址的增加,它以 LSB 到 MSB 的顺序存储多字节值。它的位编号约定是 b0 = 2^0 和 b31 = 2^31。

摩托罗拉 68000 被称为 Inconsistent Big Endian,因为随着内存地址的增加,它以 MSB 到 LSB 的顺序存储多字节值。它的位编号约定是 b0 = 2^0 和 b31 = 2^31(与 intel 相同,这就是它被称为“不一致”大端序的原因)。

32 位 IBM/Motorola PowerPC 被称为 Consistent Big Endian,因为随着内存地址的增加,它以 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任务全错了:)

重要的是要注意 abool*的大小int*与 a 的大小相同BigStruct*。同一台机器上的所有指针大小相同——32 位机器上为 32 位,64 位机器上为 64 位。

ptr + i正在向地址添加i字节ptr。何时i>3,您正在阅读一个全新的单词……这可能会导致段错误。

您要使用的是位掩码。像这样的东西应该工作:

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

您的机器几乎可以肯定无法寻址单个内存位,因此字节内的位布局是没有意义的。字节序仅指多字节对象内的字节顺序。

为了使您的第二个程序有意义(尽管实际上没有任何理由,因为它不会给您任何有意义的结果),您需要了解按位运算符 - 特别是&对于此应用程序。

于 2010-05-28T20:40:18.130 回答
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
};

In this the bit endianness is compiler dependant. Should y be the most or least significant bit in a thing? Who knows? If you care about the bit ordering (describing things like the layout of a IPv4 packet header, control registers of device, or just a storage formate in a file) then you probably don't want to worry about some different compiler doing this the wrong way. Also, compilers aren't always as smart about how they work with bit fields as one would hope.

于 2010-05-28T22:21:04.717 回答
2

这一行在这里:

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

...当您像这样进行指针运算时,编译器将指针移动到您添加的数字乘以您所指向的东西的大小。因为您将 void* 转换为 bool*,所以编译器会将指针移动一个“bool”的大小,这可能只是一个 int,因此您将从更远的地方打印出内存比你想象的要好。

您无法在一个字节中寻址各个位,因此询问它们以哪种方式存储几乎没有意义。(您的机器可以以任何它想要的方式存储它们,而您将无法分辨)。您可能会关心它的唯一时间是当您通过 I2C 或 RS232 或类似的物理接口实际吐出位时,您必须实际逐个吐出位。尽管如此,协议仍会定义将位吐出的顺序,并且设备驱动程序代码必须在“一个值为 0xAABBCCDD 的 int”和“一个位序列 11100011 ... [whatever] 在协议顺序中进行转换” ”。

于 2010-05-28T20:49:27.223 回答