我试着去了解C语言编程内存的字节顺序,但我很迷惑。我尽我的应用程序与本网站的我的输出验证某个值:www.yolinux.com/TUTORIALS/Endian-Byte-Order.html
对于我在我的C程序中使用的64位值:
volatile long long ll = (long long)1099511892096;
__mingw_printf("\tlong long, %u Bytes, %u bits,\t%lld to %lli, %lli, 0x%016llX\n", sizeof(long long), sizeof(long long)*8, LLONG_MIN, LLONG_MAX , ll, ll);
void printBits(size_t const size, void const * const ptr)
{
unsigned char *b = (unsigned char*) ptr;
unsigned char byte;
int i, j;
printf("\t");
for (i=size-1;i>=0;i--)
{
for (j=7;j>=0;j--)
{
byte = b[i] & (1<<j);
byte >>= j;
printf("%u", byte);
}
printf(" ");
}
puts("");
}
退房
long long, 8 Bytes, 64 bits, -9223372036854775808 to 9223372036854775807, 1099511892096, 0x0000010000040880
80 08 04 00 00 01 00 00 (Little-Endian)
10000000 00001000 00000100 00000000 00000000 00000001 00000000 00000000
00 00 01 00 00 04 08 80 (Big-Endian)
00000000 00000000 00000001 00000000 00000000 00000100 00001000 10000000
测试
0x8008040000010000, 1000000000001000000001000000000000000000000000010000000000000000 // online website hex2bin conv.
1000000000001000000001000000000000000000000000010000000000000000 // my C app
0x8008040000010000, 1000010000001000000001000000000000000100000000010000000000000000 // yolinux.com
0x0000010000040880, 0000000000000000000000010000000000000000000001000000100010000000 //online website hex2bin conv., 1099511892096 ! OK
0000000000000000000000010000000000000000000001000000100010000000 // my C app, 1099511892096 ! OK
[Convert]::ToInt64("0000000000000000000000010000000000000000000001000000100010000000", 2) // using powershell for other verif., 1099511892096 ! OK
0x0000010000040880, 0000000000000000000000010000010000000000000001000000100010000100 // yolinux.com, 1116691761284 (from powershell bin conv.) ! BAD !
问题
yolinux.com网站公布0x0000010000040880大端!但我的电脑使用小端,我认为(英特尔PROC)和我从我的C应用程序,并从其他网站HEX2BIN转换器得到相同的值0x0000010000040880。 __mingw_printf(...为0x%016llX ...,... LL)也打印0x0000010000040880,你可以看到。
继yolinux网站我在输出的时刻倒我“(小端)”和“(大型)”的标签。
此外,符号位必须为0的正数。这是对我的结果的情况下,也yolinux的结果。(不能帮我可以肯定的。)
如果我理解正确的字节顺序仅字节交换而不是位和我一组位似乎是正确的反转。
这简直就是yolinux.com错误或我缺少一个步骤,大约64位数字和C编程?
当您使用printf
(和正确的格式说明)打印一些“多字节”整数不要紧系统是很少或大端。其结果将是相同的。
小与大尾数之间的不同之处在于多字节类型存储在内存中的顺序。但是,一旦数据被从存储器读入核处理器,没有任何区别。
此代码显示的整数(4个字节)是如何放置在存储器我的机器上。
#include <stdio.h>
int main()
{
unsigned int u = 0x12345678;
printf("size of int is %zu\n", sizeof u);
printf("DEC: u=%u\n", u);
printf("HEX: u=0x%x\n", u);
printf("memory order:\n");
unsigned char * p = (unsigned char *)&u;
for(int i=0; i < sizeof u; ++i) printf("address %p holds %x\n", (void*)&p[i], p[i]);
return 0;
}
输出:
size of int is 4
DEC: u=305419896
HEX: u=0x12345678
memory order:
address 0x7ffddf2c263c holds 78
address 0x7ffddf2c263d holds 56
address 0x7ffddf2c263e holds 34
address 0x7ffddf2c263f holds 12
所以,我可以看到,我是一个小尾机作为对LSB(最低显著字节,即78)存储在最低的地址。
执行同一程序大端机器上会(假设同一个地址)显示:
size of int is 4
DEC: u=305419896
HEX: u=0x12345678
memory order:
address 0x7ffddf2c263c holds 12
address 0x7ffddf2c263d holds 34
address 0x7ffddf2c263e holds 56
address 0x7ffddf2c263f holds 78
现在是MSB(最高显著字节,即12)上存储的最低地址。
要了解的重要一点是,这仅涉及到“多字节类型是如何存储在内存中”。一旦整数从存储器中读取到核心内部寄存器,寄存器将持有形式0x12345678的两个小和大端机器的整数。
只有代表十进制,二进制或十六进制格式的整数单一方式。例如,数43981
等于当为十六进制写入0xABCD
,或在二进制0b1010101111001101
。任何其他值(0xCDAB
,0xDCBA
或类似的)代表一个不同的号码。
你的编译器和CPU选择内部存储该值的方法是无关紧要的,只要C标准而言;如果你特别不走运的值可以存储为一个36-bit one's complement,只要按标准规定的所有操作都具有同等的效果。
你将很少有编程时检查你的内部数据表示。实际上,当你关心字节序的唯一时间是在通信协议工作时,因为这时的数据的二进制格式必须精确定义,但即使如此,你的代码不会不同的架构,不管:
// input value is big endian, this is defined
// by the communication protocol
uint32_t parse_comm_value(const char * ptr)
{
// but bit shifts in C have the same
// meaning regardless of the endianness
// of your architecture
uint32_t result = 0;
result |= (*ptr++) << 24;
result |= (*ptr++) << 16;
result |= (*ptr++) << 8;
result |= (*ptr++);
return result;
}
文艺青年最爱的调用的标准功能像printf("0x%llx", number);
始终打印使用指定格式正确的值。通过读取单个字节检查内存中的内容给你的数据在你的架构的代表性。