我读到了关于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
和(byte)指针“步行”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<<" - ";
}
}
我得到一些随机输出
即使是nos。像“32”我没有任何理智。
为什么?
答案 0 :(得分:7)
为了完整起见,机器用 字节顺序和位顺序来描述。
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相同,这就是为什么它被称为'Inconsistent'Big Endian)。
32位IBM / Motorola PowerPC称为Consistent Big Endian,因为它随着内存地址的增加以MSB到LSB的顺序存储多字节值。其位编号约定为b0 = 2 ^ 31且b31 = 2 ^ 0。
在普通的高级语言使用下,位顺序通常对开发人员是透明的。使用汇编语言编写或使用硬件时,位编号确实起作用。
答案 1 :(得分:5)
Endianness,正如您在实验中发现的那样,是指字节存储在对象中的顺序。
比特不会以不同的方式存储,它们总是8位,并且总是“人类可读”(高 - >低)。
现在我们已经讨论过您不需要代码......关于您的代码:
for(int i=0;i<32;i++)
{
temp = *( (bool*)ptr + i );
...
}
这不是你认为它正在做的事情。你正在迭代0-32,一个字中的位数 - 很好。但是你的temp
作业完全没错:)
值得注意的是,bool*
的大小与int*
的大小相同BigStruct*
。同一台机器上的所有指针大小相同 - 32位机器上为32位,64位机器上为64位。
ptr + i
正在向i
地址添加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;
...
}
答案 2 :(得分:3)
您的机器几乎肯定无法处理单个内存位,因此字节内的位布局毫无意义。字节序仅指多字节对象内的字节顺序。
为了使你的第二个程序有意义(虽然没有任何理由,因为它不会给你任何有意义的结果)你需要了解按位运算符 - 特别是&
这个应用程序
答案 3 :(得分: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的“特性”,它允许你告诉编译器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
应该是{{1}}中最重要还是最不重要的位?谁知道?如果您关心位排序(描述IPv4包头的布局,设备的控制寄存器,或文件中的存储格式),那么您可能不想担心某些不同的编译器这样做错误办法。此外,编译器并不总是像人们希望的那样聪明地使用位字段。
答案 4 :(得分:2)
这一行:
temp = *( (bool*)ptr + i );
...当您像这样进行指针运算时,编译器会将指针移动乘以您指向的事物的大小。因为你将void *转换为bool *,编译器会将指针移动一个“bool”的大小,这可能只是一个int下的封面,所以你将从更远的地方打印内存比你想象的还要好。
您无法解决字节中的各个位,因此询问它们存储的方向几乎毫无意义。 (您的机器可以按照您想要的方式存储它们,您将无法分辨)。你可能唯一需要关心的是当你实际通过物理接口(如I2C或RS232或类似物)吐出位时,你必须逐个吐出这些位。尽管如此,协议将定义将位吐出的顺序,并且设备驱动程序代码必须在协议顺序中的“一个值为0xAABBCCDD的int”和“一个位序列11100011 ... [无论如何]之间进行转换”