Are large end and minor values ​​transferable?

Hi, I have a little little little little end and a big endian. I know this question has been asked n times, but I couldn't understand some of the below.

lets take int i = 10, it is stored in binary as 00000000 00000000 00000000 00001010

in the stack section as shown below: -

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

      

In this, both small and large endian will give the same result 10?

Then what is the use of these small and large endians?


I was asked to implement code that would be portable to the entire system, large or small, in my interview. I answered:

the compiler will do it itself as if int i = 10 in small endian then big endian also has 10 as output

Is this answer correct?

+3


source to share


4 answers


00000000 | 00000000 | 00000000 | 00001010 // big    endian

00001010 | 00000000 | 00000000 | 00000000 // little endian

      

Will the data be stored in large-entid or small-end mode, mostly only if you are trying to access a smaller portion of a variable in memory, usually with a pointer, for example trying to access the least significant character 32- bit integer via a pointer to a character or concatenation with an array of characters. Another example of a problem is reading data from a file directly into an array of 32-bit integers, or writing data from an array of 32-bit integers. The data in the file, as a rule, is also stored in the mode with a small endian or a large endian.

As far as I know, there is no generic compile-time method to determine if a processor is operating in big end mode or small end mode (specific compilers can be defined for this). You can write test code using a 32-bit integer concatenation and a size 4 character array. Then set the integer in the concatenation to 10 and check if the concatenation character array [0] contains 10, which means a small end value, or if the character array concatenation [3] contains 10, which means big end mode. There are other ways to determine if a processor is in low-entitle or high-endian mode.



Once you determine if the processor is in low-entitle or large-endian mode, you can enable conditional code to handle both cases, such as file I / O to / from an array of 32-bit integers. If you want the file data to be in big end mode, but your processor is in small end mode, you will have to flip the bytes of each integer before writing or after reading from the file.

You can also write sequences of code to store data in big endian mode, regardless of cpu mode. This will waste time if already in big endian mode, but works for both large and small mode:

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;

      

+4


source


Just fix the diagram for an integer: 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

      



In a small value, the least significant byte (LSB) is stored in the smallest memory address.

Large Sign The Most Significant Byte (MSB) is stored in the smallest memory address.

+1


source


First of all: you are actually confusing high-order and low-order byte ordering as @ rcgldr's and @ Galik's answers . The byte ordering is exactly the opposite as you show in your example:

00000000 | 00000000 | 00000000 | 00001010 // big endian

00001010 | 00000000 | 00000000 | 00000000 // little endian

      


As for your guesses and questions:

"In this, both small and large endian will give the same result 10?

It depends on the kind of output you are talking about.

  • The following code will be portable regardless of the target machine of the host, the output will be formatted text ( "10"

    ) anyway:

int i = 10;

std::cout << i << std::endl;

      


  1. The following code will not be portable. Since the values ​​are written in binary, the byte order will be stored verbatim:
int i = 10;

std::ofstream binfile("binaryfile.bin");
binfile.write((const char*)&i,sizeof(int));

      


The last sample will not work if the file is to be read on a host machine with a different endianess.

To solve these problems, there exists a family of functions , . Usually agrees to use the big-endian format for storing binary data or sending over a network. htonl()

ntohl()

Here's a quick reference on how to use the listed byte order conversion functions:


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

      


"Then what is the use of these small and large endians?"

The reason (usage) for different formats is that there are different processor architectures that use different ways to represent integer values ​​in memory, depending on which is the most efficient way to access them for their particular hardware design.
There is no worse / better for these architectural differences, so it was called endianess. The very origin of this coinage comes from Jonathan Swift's novel "Gulliver's Journey" and was the first (?) Mentioned in Daniel Cohen's article "ON THE SACRED WARS AND THE PEACE . "


"the compiler will do it itself, as if int i = 10 in little endian, then in big endian also 10 as output"

Well, as you can see from the examples above, this answer was wrong.

+1


source


The limb matters in the following situations:

  • You directly learn / manipulate bytes in a multibyte type
  • Are you serializing binary data or transferring binary data between different architectures

Direct exploration / manipulation of bytes in multibyte type

For example, suppose you want to split and display the binary representation of a 32-bit IEEE float. The following shows the location of floats and corresponding byte addresses in both the large and small end architectures:

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)

      

The sign bit is in the most significant byte (MSB) of the float. On a system with large terms, the MSB is in a byte A

; on a little-endian system, it is in byte A + 3. On some fuzzy bars, such as the old VAX F flop, it is stuck in the middle in byte A+1

.

So, if you want to mask the sign bit, you can do something like the following:

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

      

Serializing or transferring binary data

In another example, you want to store binary (rather than text) data so that it can be read by systems with large or small names, or you are transferring binary data from one system to another. The convention for internet transfers is broadband (MSB first), so you must use calls like htonl

(network-to-network long network) and htons

(host to -network short) to perform any required byte swaps before sending a message over "network" before sending data:

uint32_t host_value = some_value();
uint32_t network_value = htonl( host_value ); 
send( sock, &network_value, sizeof network_value, 0 ); 

      

On a small system like x86 htonl

will change the byte order host_value

from 0,1,2,3 to 3,2,1,0 and store the result up to network_value

. The system with a lot of enthusiasm htonl

mostly does not work. Reverse operations: ntohl

and ntohs

.

If you don't do anything like the above, then you don't need to worry about content at all.

+1


source







All Articles