[英]Are big endian and little endian values portable?
你好,我有一个小端dout和大端的小dout我知道这个问题已经问过n次但我无法弄清楚以下几点
让我们把int i = 10它以二进制形式存储为00000000 00000000 00000000 00001010
在堆栈部分如下: -
00000000 |00000000 |00000000 |00001010 // In case of little endian
MSB-------------------------------------------LSB
大端
00001010 |00000000 |00000000 |00000000 // In case of in big endian
MSB-------------------------------------------LSB
在这个小端和大端都将给出相同的输出10?
那么这些小端和大端的用途是什么?
我被要求实现代码,这些代码可以在我的访谈中对所有大小系统都是可移植的。 我回答说:
编译器会自己做,如果int i = 10 in little endian,那么在big endian中它也是10作为输出
这个答案是否正确?
00000000 | 00000000 | 00000000 | 00001010 // big endian
00001010 | 00000000 | 00000000 | 00000000 // little endian
无论数据是以big endian还是little endian模式存储,大多数情况下,只有当你试图通过指针访问内存中较小部分的变量时才会很重要,就像试图通过a访问32位整数的最低有效字符一样指向字符的指针或带有字符数组的联合。 另一个问题的例子是,如果您将文件中的数据直接读取到32位整数数组中,或者从32位整数数组中读取数据。 文件中的数据通常也以小端或大端模式存储。
据我所知,没有通用的编译时方法来确定cpu是以big endian模式还是little endian模式运行(特定的编译器可能已为此定义)。 您可以使用32位整数和大小为4的字符数组的并集编写测试代码。然后将union中的整数设置为10,并检查union字符数组[0]是否包含10表示小端模式,或者如果联合字符数组[3]包含10,这意味着大端模式。 可以使用其他方法来确定CPU是处于小端还是大端模式。
一旦确定cpu是处于小端还是大端模式,就可以包含条件代码来处理这两种情况,例如来自/来自32位整数数组的文件I / O. 如果您希望文件数据处于大端模式,但您的cpu处于小端模式,则必须在写入之前或从文件读取之后反转每个整数的字节。
无论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;
只是为了修正你的整数图: 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
在小端 , 最低有效字节 (LSB)存储在最低存储器地址中。
在big endian中 , 最高有效字节 (MSB)存储在最低内存地址中。
首先:你实际上混淆了big -little-endian字节顺序,正如@ rcgldr和@ Galik的回答所指出的那样。 正如您在样本中显示的那样,字节顺序完全相反:
00000000 | 00000000 | 00000000 | 00001010 // big endian
00001010 | 00000000 | 00000000 | 00000000 // little endian
至于你的假设和问题:
“在这个小端和大端都将给出相同的输出10?”
这取决于你所指的输出类型 。
"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
“那么这些小端和大端的用途是什么?”
不同格式的原因(使用)是,有不同的CPU架构,使用不同的方式在内存中表示整数值,这取决于访问它们的特定硬件设计的最有效方式。
这些架构差异并没有更糟/更好,这就是为什么它被称为endianess 。 这个造币的起源来自Johnatan Swift的小说“格列佛的旅行”,并且是Daniel Cohen的文章“关于和平的战争和和平的和平”中提到的第一个(?)。
“编译器会自行完成,如果int i = 10 in little endian,那么在big endian中它也是10作为输出”
好吧,正如你从上面的例子中看到的那样,这个答案是错误的。
字节顺序在以下情况下很重要:
直接检查/操作多字节类型的字节
例如,假设您要拆分并显示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
序列化或传输二进制数据
再举一个例子,您希望保存二进制(非文本)数据,使其可以被大端或小端系统读取,或者您将二进制数据从一个系统传输到另一个系统。 Internet传输的约定是big-endian(MSB优先),所以在通过'net发送消息之前,你会使用像htonl
(host-to-network long)和htons
(host-to-network short)这样的调用在发送数据之前执行任何必要的字节交换:
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并将结果保存到network_value
。 在大端系统上, htonl
基本上是一个无操作系统。 逆操作是ntohl
和ntohs
。
如果您没有做上述任何事情,那么您通常不必担心字节序。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.