Memory storage | How to store integer in memory | Original code one’s complement | Big and small endian

Storage of integers in memory

There are three representation forms of integers in binary: original code, complement code, and complement code.

  • Positive integer: original code, complement code and complement code are the same
  • Negative integer: original code, complement code, complement code need to be calculated

Integers are stored in memory as two’s complement binary sequences.

For signed integers, the highest bit in the binary system is the sign bit. The highest bit is “0”, which represents a positive number, and the highest bit, which is “1”, represents a negative number.

SoWhy is the complement code stored in memory?

Using complement codes, sign bits and numerical fields can be processed uniformly, and addition and subtraction can also be processed uniformly. There is only an adder in the CPU, and the complement code and the original code are converted to each other. The operation process is the same and no additional hardware circuit is required.

Let’s give an example:

1-1

Because there are only adders in the CPU, the subtraction method is 1 + (-1).

1’s complement: 00000000 00000000 00000000 00000001

-1’s complement: 111111111 11111111 11111111 11111111

1 + (-1): 00000000 00000000 00000000 00000000

In the same way, when performing multiplication and subtraction, multiple numbers are added and multiple numbers are subtracted.

From the above example, we can indeed get that what is stored is the complement, but why does the order of storage change?

Introduction to big and small endian

When we create variables, the operating system will allocate space to you. For example, if you create [short/int/double/float] variables, the types of these variables are greater than 1 byte. The operating system will allocate space to you based on your According to the type of the variable, the corresponding memory space is allocated. After the space is allocated, the variable is stored in this memory. Anyway, the memory has been divided, so how to store it in this memory has nothing to do with the operating system. So does this variable go from low address to high address in its memory storage? Or from high address to low address?

In a given piece of memory, when storing in memory, the order can be arbitrary. As long as you store it in your way, the key is to return it in your way when you need to use the data.

In short, it doesn’t really matter how you store it. What matters is that you can store it in and take it out.

As shown in the figure below, assuming int a = 0x11223344, in fact, the following storage methods are all possible, but because the following two storage methods are extremely inconvenient when reading, so the following C In the process of language development, storage methods similar to the following will no longer be used. Finally, these two storage methods were adopted, one is to store forward, and the other is to store backward.

This is divided into two storage methods, big-endian byte order storage and little-endian byte order storage.

Big endian storage

Big-endian storage is to store the data at the lower byte of a data into the higher byte of the data in memory, and then store the data at the higher byte of the data. The data at the high-order byteis stored in the memory to the stored data at the low-order byte.

Little-endian storage

Little-endian byte order storage is to store the data at the high byte of a data into the high byte of the data, and then store the data at the high byte of the data. The data at the lower byte is stored in the memory. The data at the lower byte is stored.

Note here that when the data type is char, there is no need to consider the storage order, because char type data only occupies 1 byte.

Only when the number of bytes occupied is greater than 1 byte, such as short, int, double, float, long long, etc., we will consider the issue of storage order.

So why does the storage problem of big and small endian byte order occur?

Because in computer systems, we use bytes as units, each address unit corresponds to a byte, and a byte is 8 bits. But in C language, in addition to 8-bit char, there are also 16-bit short and 32-bit long (specifically, it depends on the compiler). In addition, for 16-bit and 32-bit processors, since the register is larger than one byte, there must be a problem of how to arrange a multi-byte storage, which leads to big and small endian storage. divided.

After studying Big-endian byte order storage, here is a written test question about it:

Baidu’s 2015 system engineer written examination questions:

Please briefly describe the concepts of big-endian byte order storage and little-endian byte order storage, and design a program to determine the byte order of the current machine.

Ideas:

If we store int a=0, then the hexadecimal notation of a is0x 00 00 00 01. In this data, the 01 direction is the low-digit data, and the 00 direction is the high-digit data. Then, in this case, 1 is stored, assuming it is stored in little-endian order (high-digit data is stored in the high address), then 01 is stored in the high address, then as long as it is verified that the number taken out from the low address is equal to 1 If so, then it can be explained that it is little-endian storage. As shown in the picture:

Code:

#include <stdio.h>
int main()
{
int a = 1;
char* p = (char*) & amp;a;//Use 1 byte of char type to determine the value of one byte of data stored at the low address
if(*p==1)
{
printf("little endian");
}
else
{
printf("Big Endian");
}
return 0;
}

Here are a few examples, let’s take a look:

Examples related to integer storage

  • What is the result of running the following code:
#include <stdio.h>
int main()
{
char a = -1;
signed char b = -1;
unsigned char c = -1;
\t
printf("%d %d %d", a, b, c);
return 0;
}

Analysis:

  • -1’s complement: 11111111 11111111 11111111 11111111
  • The above is the storage method of -1 in integer type, and char only occupies 1 byte, so the complement code of char -1 stored in computer memory is: 11111111
  • %d prints a signed integer in decimal form
  • But now it is a char type, not an integer type, so the integer type is promoted.
  • Rules for integer promotion: For signed numbers, integer promotion adds its sign bit; for unsigned integers, it adds 0.
  • And because the char type is signed on most compilers, the integer type promotes the sign bit.
  • So the printed complement of char a=-1 is: 11111111 11111111 11111111 11111111
  • So the corresponding integer type is -1, so the printed result of the first value is -1.

operation result:

-1 -1 255

  • What is the result of running the following code:
#include <stdio.h>
int main()
{
char a = -128;
printf("%u\\
", a);
}

Analysis:

  • The complement of -128: 11111111 11111111 11111111 10000000
  • But the above is the integer type -128. The integer type occupies 4 bytes, while the char type only occupies 1 byte. Therefore, the complement code of char -128 can only be stored in the computer memory: 10000000.
  • %u is in decimal form, printing an unsigned integer;
  • Now this -128 is not an integer type, but a character type, so integer promotion is needed;
  • Rules for integer promotion: For signed numbers, integer promotion adds its sign bit; for unsigned integers, it adds 0.
  • And because the char type is signed on most compilers, the integer type promotes the sign bit;
  • So the printed complement of char a=-128 is: 11111111 11111111 11111111 10000000
  • And %u prints an unsigned integer, so all bits in the entire binary are valid bits and there is no sign bit;
  • So the corresponding integer type is 4,294,967,168, so the first value printed is 4,294,967,168.
  • What is the result of running the following code:
#include <stdio.h>
int main()
{
char a = 128;
printf("%u\\
", a);
}

Analysis:

  • 128’s complement: 00000000 00000000 00000000 10000000
  • But the above is the integer type 128. The integer type occupies 4 bytes, while the char type only occupies 1 byte. Therefore, the complement code that char128 can only store in computer memory is: 10000000.
  • %u is in decimal form, printing an unsigned integer;
  • And now this 128 is not an integer type, but a character type, so it needs integer promotion;
  • Rules for integer promotion: For signed numbers, integer promotion adds its sign bit; for unsigned integers, it adds 0.
  • And because the char type is signed on most compilers, the integer type promotes the sign bit;
  • So the printed complement of char a=128 is: 11111111 11111111 11111111 10000000
  • And %u prints an unsigned integer, so all bits in the entire binary are valid bits and there is no sign bit;
  • So the corresponding integer type is 4,294,967,168, so the first value printed is 4,294,967,168.
  • What is the result of running the following code:
#include <stdio.h>
int main()
{
int i = -20;
unsigned int j = 10;
printf("%d\\
", i + j);
}

Analysis:

  • -20’s complement: 11111111 11111111 11111111 11101100
  • 10’s complement: 00000000 00000000 00000000 00001010
  • The result’s complement of -20’s complement + 10’s complement: 11111111 11111111 11111111 11110110
  • Original code: 10000000 00000000 00000000 00001010

Running result: -10

  • What is the result of running the following code:
#include <stdio.h>
int main()
{
unsigned int i;
for (i = 9; i >= 0; i--)
{
printf("%u\\
", i);
Sleep(1000);
}
return 0;
}

Analysis:

Note that this is an unsigned char type, and any unsigned integer is greater than or equal to zero. If it is unsigned, then each bit of it is a significant number. After reducing to 0, it becomes:

11111111 11111111 11111111 11111111

11111111 11111111 11111111 11111110

11111111 11111111 11111111 11111101

11111111 11111111 11111111 11111100

i here has always been regarded as an integer and i is greater than or equal to 0, so it enters an infinite loop.

The reincarnation of unsigned and signed:

  • What is the result of running the following code:
#include <stdio.h>
int main()
{
char a[1000];
int i = 0;
for (i = 0; i < 1000; i + + )
{
a[i] = -1 - i;
}
printf("%d", strlen(a));
return 0;
}

Analysis:

  • strlen counts the number of characters that appear before “\0”
  • “\0” is a character in the form of “\ddd”, and its ASCII code value is 0
  • So this question is to count when 0 is encountered in this array.
  • char is signed in most compilers, so:
  • The running process is: -1 -2 -3 -4 -5 -6…-128 127…6 5 4 3 2 1
  • 128 + 127=255

Running result: 255

  • What is the result of running the following code:
#include <stdio.h>
unsigned char i = 0;
int main()
{
for (i = 0; i <= 255; i + + )
{
printf("hello world\\
");
}
return 0;
}

Analysis:

The value range of unsigned char is 0~255

So i<=255, so an infinite loop