你好,我有一个小端dout和大端的小dout我知道这个问题已经问了n次,但我无法弄清楚以下几点
让int i = 10它在二进制文件中以00000000 00000000 00000000 00001010
的形式存储在堆栈部分中,如下所示: -
00000000 |00000000 |00000000 |00001010 // In case of little endian
MSB-------------------------------------------LSB
Big endian
00001010 |00000000 |00000000 |00000000 // In case of in big endian
MSB-------------------------------------------LSB
在这个小端和大端都会给出相同的输出10?
那么这些小端和大端的用途是什么?
我被要求实现代码,这些代码在我的访谈中对于所有大小系统都是可移植的。我回答说:
编译器会自行完成,如果int i = 10 in little endian,那么在big endian中它也是10作为输出
答案是否正确?
答案 0 :(得分:4)
00000000 | 00000000 | 00000000 | 00001010 // big endian
00001010 | 00000000 | 00000000 | 00000000 // little endian
数据是以big endian还是little endian模式存储,这通常只会影响您是否尝试通过指针访问内存中较小部分的变量,例如尝试访问a中最不重要的字符。通过指向字符的指针或带字符数组的并集的32位整数。另一个问题的例子是,如果您将文件中的数据直接读取到32位整数数组中,或者从32位整数数组中读取数据。文件中的数据通常也会以小端或大端模式存储。
据我所知,没有通用的编译时方法来确定cpu是以大端模式还是小端模式运行(特定编译器可能已为此定义)。您可以使用32位整数和大小为4的字符数组的并集编写测试代码。然后将union中的整数设置为10,并检查union字符数组[0]是否包含10表示小端模式,或者如果联合字符数组[3]包含10,这意味着大端模式。可以使用其他方法来确定CPU是处于小端还是大端模式。
一旦确定cpu是处于小端还是大端模式,就可以包含条件代码来处理这两种情况,例如来自/来自32位整数数组的文件I / O.如果您希望文件数据处于大端模式,但您的cpu处于小端模式,则在写入之前或从文件读取之后,您必须反转每个整数的字节。
您也可以编写代码序列来以big endian模式存储数据,而不管cpu模式如何。如果已经处于大端模式,它将浪费时间,但它适用于大端和小端模式:
char buffer[256];
char * ptr2char;
uint32_t uint32bit;
/* ... */
ptr2char = buffer; /* store uint32bit in big endian mode */
*ptr2char++ = (uint32bit >> 24)&0xff;
*ptr2char++ = (uint32bit >> 16)&0xff;
*ptr2char++ = (uint32bit >> 8)&0xff;
*ptr2char++ = (uint32bit )&0xff;
答案 1 :(得分:1)
只需更正整数的图表:int i = 10;
// Big endian
&i <- address of i
00000000 |00000000 |00000000 |00001010 // In case of big endian
MSB---------------------------LSB
// Lower memory -----------------> higher memory
// Little endian
00001010 |00000000 |00000000 |00000000 // In case of in little endian
&i <- address of i
LSB---------------------------MSB
在 little endian 中,最低有效字节(LSB)存储在最低内存地址中。
在 big endian 中,最高有效字节(MSB)存储在最低内存地址中。
答案 2 :(得分:1)
首先:您确实混淆了大端和小端字节顺序,正如@rcgldr's和@Galik's答案中所指出的那样。正如您在样本中显示的那样,字节顺序完全相反:
00000000 | 00000000 | 00000000 | 00001010 // big endian
00001010 | 00000000 | 00000000 | 00000000 // little endian
至于你的假设和问题:
&#34;在这个小端和大端都会给出相同的输出10?&#34;
这取决于您所指的 输出类型 。
"10"
)在任何情况下:int i = 10;
std::cout << i << std::endl;
int i = 10;
std::ofstream binfile("binaryfile.bin");
binfile.write((const char*)&i,sizeof(int));
如果应在具有不同字节顺序的主机上读取文件,则后一个示例将无效。
为了解决这类问题,htonl()
, ntohl()
函数族已经出现。通常,人们同意使用网络字节顺序(big-endian)格式来存储二进制数据或通过网络发送它。
这是一个简短的示例,如何使用上面提到的字节顺序转换函数:
int i = 10;
int sendValue = htonl(i); // convert the value of i to network byte order
std::ofstream binfile("binaryfile.bin");
binfile.write((const char*)&sendValue,sizeof(int)); // write the adapted value
std::ifstream binfile("binaryfile.bin");
int recvValue = 0;
binfile.read((char*)&recvValue,sizeof(int)); // read the value in network byte order
int i = ntohl(recvValue); // convert the value of recvValue to host byte order
&#34;那么这些小端和大端的用途是什么?&#34;
不同格式的原因(使用)是,有不同的CPU架构,它们使用不同的方式在内存中表示整数值,具体取决于访问它们的特定硬件设计的最有效方式。
这些架构差异并没有更糟/更好,这就是为什么它被称为 endianess 。这个造币的起源来自Johnatan Swift的小说&#34; Gulliver's travels&#34; 并且是Daniel Cohen的文章中提到的第一个(?) "ON HOLY WARS AND A PLEA FOR PEACE"
&#34;编译器将自行完成,如果int i = 10 in little endian,那么在big endian中它也是10作为输出&#34;
好吧,正如你从上面的例子中看到的那样,答案是错误的。
答案 3 :(得分:1)
直接检查/操作多字节类型中的字节
例如,假设您要拆分并显示32位IEEE浮点的二进制表示。下面显示了float和big-little-endian体系结构中float的布局和相应字节的地址:
A A+1 A+2 A+3 Big endian
-------- -------- -------- -------- s = sign bit
seeeeeee efffffff ffffffff ffffffff e = exponent bit
-------- -------- -------- -------- f = fraction bit
A+3 A+2 A+1 A Little Endian
-------- -------- -------- --------
A+1 A A+3 A+2 "Middle" Endian (VAX)
符号位在float的最高有效字节(MSB)中。在大端系统上,MSB是字节A
;在小端系统上,它在字节A + 3中。在像旧的VAX F浮点数这样的奇怪的球上,它被卡在中间的A+1
字节处。
因此,如果你想掩盖符号位,你可以执行以下操作:
float val = some_value();
unsigned char *p = (unsigned char *) &val; // treat val as an array of unsigned char
// Assume big-endian to begin with
int idx = 0;
if ( little_endian() )
idx = 3;
int sign = (p[idx] & 0x80) >> 7
序列化或传输二进制数据
再例如,您希望保存二进制(非文本)数据,以便大端或小端系统可以读取数据,或者将二进制数据从一个系统传输到另一个系统。互联网传输的惯例是big-endian(MSB优先),因此在通过'net发送消息之前,您使用htonl
(主机到网络长)和htons
等呼叫(主机到网络短路)在发送数据之前执行任何必要的字节交换:
uint32_t host_value = some_value();
uint32_t network_value = htonl( host_value );
send( sock, &network_value, sizeof network_value, 0 );
在像x86这样的小端系统上,htonl
会将host_value
的字节从0,1,2,3重新排序到3,2,1,0并将结果保存到{{ 1}}。在大端系统上,network_value
基本上是无操作系统。逆操作是htonl
和ntohl
。
如果您不做上述事情,那么您通常不必担心字节序。