如何根据“Endianness”将数据存储在位级别?

我读到关于Endianness并理解蹲下……

所以我写了这个

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”我没有得到任何明智的东西。

为什么?

您通过实验发现的Endianness指的是字节存储在对象中的顺序。

比特不会以不同的方式存储,它们总是8位,并且总是“人类可读”(高 – >低)。

现在我们已经讨论过你不需要代码……关于你的代码:

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

这不是你认为它正在做的事情。 你正在迭代0-32,一个字中的位数 - 很好。 但你的temp任务是错的:)

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

ptr + ii字节添加到ptr地址。 当i>3 ,你正在读一个全新的词......这可能会引起一个段错误。

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

 for (int i = 0; i < 32; i++) { unsigned int mask = 1 << i; bool bit_is_one = static_cast(ptr) & mask; ... } 

仅仅为了完整性,机器是按字节顺序和位顺序来描述的。

intel x86被称为Consistent Little Endian,因为它随着内存地址的增加以LSB到MSB顺序存储多字节值。 其位编号约定为b0 = 2 ^ 0且b31 = 2 ^ 31。

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

32位IBM / Motorola PowerPC称为Consistent Big Endian,因为它随着内存地址的增加以MSB到LSB的顺序存储多字节值。 其位编号约定为b0 = 2 ^ 31且b31 = 2 ^ 0。

在普通的高级语言使用下,位顺序通常对开发人员是透明的。 使用汇编语言编写或使用硬件时,位编号确实起作用。

你的机器几乎肯定无法处理单个内​​存位,因此字节内的位布局毫无意义。 字节序仅指多字节对象内的字节顺序。

为了使你的第二个程序有意义(虽然没有任何理由,因为它不会给你任何有意义的结果)你需要了解按位运算符 – 特别是对于这个应用程序。

Byte Endianness

在不同的机器上,此代码可能会给出不同的结

 union endian_example { unsigned long u; unsigned char a[sizeof(unsigned long)]; } x; xu = 0x0a0b0c0d; int i; for (i = 0; i< sizeof(unsigned long); i++) { printf("%u\n", (unsigned)xa[i]); } 

这是因为不同的机器可以按任何字节顺序自由存储值。 这是相当武断的。 在宏伟的计划中没有倒退或前锋。

比特字节

通常你不必担心比特字节序。 访问各个位的最常用方法是使用移位( >><< ),但这些方法实际上与值有关,而不是字节或位。 他们对价值进行算术运算。 该值存储在位(以字节为单位)中。

如果您使用位字段,则可能在C中遇到位端字符串问题。 这是一个很少使用(因为这个原因和其他一些)C的“function”,它允许您告诉编译器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 }; 

在这种情况下,位字节式取决于编译器。 你应该是一个thing最重要或最不重要的thing吗? 谁知道? 如果您关心位排序(描述IPv4包头的布局,设备的控制寄存器,或文件中的存储格式),那么您可能不想担心某些不同的编译器这样做错误办法。 此外,编译器并不总是像人们希望的那样聪明地使用位字段。

这一行在这里:

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

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

你无法解决一个字节中的各个位,因此询问它们存储的方向几乎毫无意义。 (您的机器可以按照您想要的方式存储它们,您将无法分辨)。 您可能唯一需要关心的是当您实际通过I2C或RS232等物理接口吐出位时,您必须逐个吐出这些位。 尽管如此,协议还是会定义将位吐出的顺序,并且设备驱动程序代码必须在协议顺序中的“一个值为0xAABBCCDD的int”和“一个位序列11100011 … [无论如何]之间进行转换”。