Cultivate internal strength [deep analysis of data storage in memory]

data storage in memory

plastic surgery

Before starting again, let's have a little preliminary knowledge, that is, what is the original code inverse code and complement code

original code

The original code can be obtained by directly translating the value into binary in the form of positive and negative numbers.

inverse code

Keep the sign bit of the original code unchanged, and invert the other bits in turn to obtain the inverse code.

Complement

Inverse code + 1 will get the complement code.

With the above foreshadowing, we can proceed to the next step
in the computer memory

There are three binary representation methods for integers in computers, namely original code, complement code and complement code.
The three representation methods all have two parts, the sign bit and the value bit. The sign bit uses 0 to represent "positive", and 1 to represent "negative"
.
There are three different ways of representing negative integers.

The binary number stored in the memory of an integer is two's complement , why is it two's complement?

In computer systems, values ​​are always expressed and stored in two's complement. The reason is that, using the complement code, the sign bit and the value field can be
processed uniformly;
at the same time, addition and subtraction can also be processed uniformly (the CPU only has an adder). In addition, the complement code and the original code are converted to each other, and the operation process
is the same. No additional hardware circuitry is required.

example

1-1
1+-1//因为CPU只有加法器
00000000000000000000000000000001//1的原码
10000000000000000000000000000001//-1的原码
11111111111111111111111111111110//-1的反码
11111111111111111111111111111111//-1的补码
00000000000000000000000000000001//相加
100000000000000000000000000000000//进1,截断多余的部分,即为0

When using the original code to add the original code

00000000000000000000000000000001//1的原码
10000000000000000000000000000001//-1的原码
10000000000000000000000000000010//结果为-2

From the above example, it can be clearly seen that the two’s complement code
is used for calculation in the memory . When running in VS, you can see that

insert image description here

The original negation of positive numbers is the same, and 0x represents the hexadecimal representation

-1 stores all ones, and the hexadecimal representation displays ff ff ff ff

-1 stores all 1, and the hexadecimal representation shows ff ff ff ff

But we found a suspicious phenomenon.
Why is the storage in a reversed?
This has to say what is big endian
and small endian

:
Big endian (storage) mode means that the low bits of data are stored in the high addresses of the memory, while the high bits of data are stored in the low addresses of the memory; little endian (
storage
) mode means that the low bits of data are stored in the memory In the low address, while the high bit of the data, is stored in the high
address of the memory.

insert image description here
Diagram as above

The next step is to consolidate in time
, which is a Baidu interview question.

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

We have finished the concept, let's
go directly to the actual operation

int check_sys()
{
    
    
     int i = 1;
     char* p=(char*)&i;
     return *p;
}
int main()
{
    
    
      int ret = check_sys();
      if(ret == 1)
     {
    
    
       printf("小端\n");
     }
      else
     {
    
    
      printf("大端\n");
     }
 return 0;
 }

topic training

( In order to strengthen the training effect, there are slightly more questions )
Question 1

1. What is the output?
#include <stdio.h>
int main()
{ char a= -1; signed char b=-1; unsigned char c=-1; printf("a=%d,b=%d,c=%d" ,a,b,c); return 0; }





-1是整数
11111111111111111111111111111111//补码
//因char只能存放8字节,故阶段多余的
11111111//a中实际存放的
//注意:%d是10进制形式,打印有符号
//     %u是10进制形式,打印无符号
//则a先整形提升
11111111111111111111111111111111
10000000000000000000000000000001//转换成原码为-1,打印的即为-1
//signed char同理
//对于unsigned char -1在c中实际存放的也是
11111111
00000000000000000000000011111111//整形提升(无符号提升0)
//故打印的为255

Question 2

#include <stdio.h>
int main()
{
char a = -128;
printf(“%u\n”,a);
return 0;
}

10000000000000000000000010000000//原码
11111111111111111111111101111111//反码
11111111111111111111111110000000//补码
10000000//a中实际存储
11111111111111111111111110000000//整形提升
//因为以%u的形式打印,每位都是有效位
结果为4294967168

Question 3

int i= -20;
unsigned int j = 10;
printf("%d\n", i+j);
//Operate in the form of two's complement, and finally format it into a signed integer

11111111111111111111111111101100//i补码
00000000000000000000000000001010//j补码
11111111111111111111111111110110//结果的补码
10000000000000000000000000001010//结果的圆码
故结果为-10

Question 4

unsigned int i;
for(i = 9; i >= 0; i–)
{
printf(“%u\n”,i);
}

That’s right, the more concise the topic, the bigger the pit.
You must know that unsigned is positive whether it is positive or negative, so it is
obvious
that the answer is an infinite loop.

Question 5

int main()
{
char a[1000];
int i;
for(i=0; i<1000; i++)
{
a[i] = -1-i;
}
printf(“%d”,strlen(a));
return 0;
}

insert image description here
Believe that you are smart after reading this pie, you must have an epiphany

floating point

Finally waiting for you ~~
First, an introduction

int main()
{
    
    
 int n = 9;
 float *pFloat = (float *)&n;
 printf("n的值为:%d\n",n);
 printf("*pFloat的值为:%f\n",*pFloat);
 *pFloat = 9.0;
 printf("num的值为:%d\n",n);
 printf("*pFloat的值为:%f\n",*pFloat);
 return 0;
}

Please think about
it and reveal the answer.
I believe everyone has no problem with 1 and 4.
insert image description here
Why does this happen?
Because of the different storage methods , it is not a simple original and inverse complement code.
As for why it is not
, please see~~

According to the international standard IEEE (Institute of Electrical and Electronics Engineering) 754, any binary floating-point number V can be expressed in the following form :

1· (-1)^S * M * 2^E
2· (-1)^S represents the sign bit, when S=0, V is a positive number; when S=1, V is a negative number.
M represents a valid number, greater than or equal to 1 and less than 2.
3· 2^E represents the exponent.

I believe that you must be confused after reading it. Let
me briefly explain
the decimal system: 5.5
is converted into binary system. Binary
system: 101.1
insert image description here
is 1.011*2^2
written according to the IEEE standard is
(-1)^0 × 1.011 ×2^2
to get
S=0;
M=1.011; //It can always be converted into the form of 1.
E=2;

then store it in the following way.
insert image description here
For 32-bit floating-point numbers, the highest 1 bit is the sign Bit s, the next 8 bits are the exponent E, and the remaining 23 bits are the significand M.
insert image description here
For a 64-bit floating-point number, the highest bit is the sign bit S, the next 11 bits are the exponent E, and the remaining 52 bits are the significand M.

Is the storage simply put in, NONONON~
For M

As mentioned earlier, 1≤M<2, that is to say, M can be written in the form of 1.xxxxxx, where xxxxxx represents the decimal part.
IEEE 754 stipulates that when M is saved inside the computer, the first digit of this number is always 1 by default, so it can be discarded, and only the following
xxxxxx part is saved. For example, when saving 1.01
, only save 01, and then add the first 1 when reading. The purpose of doing this is to save 1 significant figure. Taking the 32-bit
floating-point number as an example, there are only 23 bits left for M.
After the first 1 is discarded, 24 significant figures can be saved.

As for E , it is a little complicated and abstract (it doesn’t matter if you understand the problem, after all, it was discussed by a table of ancient bosses)

First, E is an unsigned integer (unsigned int)
, which means that if E is 8 bits, its value range is 0 255; if E is 11 bits, its value range is 0 2047. However, we
know that E in scientific notation can have
negative numbers, so IEEE 754 stipulates that an intermediate number must be added to the real value of E when stored in memory. For 8-bit E, this intermediate number
is 127 ; for 11-bit E, this intermediate
number is 1023. For example, the E of 2^10 is 10, so when saving it as a 32-bit floating point number, it must be saved as 10+127=137, which is
10001001.

E put it in and understand, the next step is how to take it out

E is not all 0 or not all 1 (usually)

At this time, the floating-point number is represented by the following rules, that is, the calculated value of the exponent E is subtracted by 127 (or 1023) to obtain the real value, and then the
first digit 1 is added before the effective number M.
For example:
The binary form of 0.5 (1/2) is 0.1. Since the positive part must be 1, that is, the decimal point is shifted to the right by 1 bit, then it is
1.0*2^(-1), and its order code is -1+127= 126, expressed as
01111110, and the mantissa 1.0 removes the integer part to be 0, fills 0 to 23 digits 000000000000000000000000, then its binary
representation is

0 01111110 00000000000000000000000

E is all 0

At this time, the exponent E of the floating-point number equal to 1-127 (or 1-1023) is the real value, and the
effective number M is no longer added with the first digit of 1, but is restored to a decimal of 0.xxxxxx. This is done to represent ±0, and
very small numbers close to 0.

E is all 1

At this time, if the significant number M is all 0, it means ± infinity (positive or negative depends on the sign bit s)

Now the opening quote can be explained
insert image description here

n中存储9
0 00000000 00000000000000000001001//正数原码即补码
&n之后强转为float*类型
以浮点型的形式打印,对照下表
则S放0,E为00000000,M为00000000000000000001001
按照(-1)^S * M * 2^E形式写出
(-1^0× 0.00000000000000000001001×2^-126
显然,V是一个很小的接近于0的正数,所以用十进制小数表示就是0.000000

insert image description here

*pFolat赋值为9.0,也就是以浮点数的形式存储
9.0的二进制
1001.0
即(-1^0×00100000×2^3
 s=0, M=1.001,E=3+127=130
 放入内存中
 0 10000010 00100000000000000000000%d的形式打印
 正是 1091567616

welcome to add

Guess you like

Origin blog.csdn.net/2301_78636079/article/details/132113486