当前位置:网站首页>Storage of data (integer, floating-point, super detailed)
Storage of data (integer, floating-point, super detailed)
2022-06-10 03:17:00 【Cloud C】
List of articles
Data type introduction
Basic built-in type :
char // Character data type // Occupy memory 1 Bytes
short // Short // Occupy memory 2 Bytes
int // integer // Occupy memory 4 Bytes
long // Long integer // Occupy memory 4/8 Bytes
long long // Longer plastic surgery // Occupy memory 8 Bytes
float // Single-precision floating-point // Occupy memory 4 Bytes
double // Double precision floating point // Occupy memory 8 Bytes
The meaning of type :
- Type determines the amount of space the data will open up in memory
- Type determines the perspective of memory spatial data
Basic classification of types :
The integer family :
char
signed char
unsigned char
short
signed short [int]
unsigned short [int]
int
signed int
unsigned int
long
signed long [int]
unsigned long [int]
long long
signed long long [int]
unsigned long long [int]
Floating point family :
float
double
Construction type :
> An array type
> Type of structure struct
> Enumeration type enum
> Joint type union
Pointer types :
char* pc;
short* ps;
int* pi;
long* pl;
long long* pll;
float* pf;
double* pd;
void* pv;
.
.
.
Empty type :
void Indicates empty type ( No type )
Usually applied to the return type of a function 、 The parameters of the function 、 Pointer types .
// first void Represents no return value
// the second void Represents that no parameters are required
void test1(void)
{
;
}
//void* For accepting any type of pointer
void test2(void* p)
{
;
}
Shaping storage in memory
Variables are created to open up space in memory , The size of the open space is determined by the type of variable .
After the space is opened up , There must be a problem of how to store data
And in the computer , Integers are stored in the form of binary complements of the data .
Original code 、 Inverse code 、 Complement code
There are three binary representations of integers in a computer , The original code 、 Inverse and complement .
There are three ways of expression Sign bit and Value bits Two parts :
Sign bit : It's all used 0 Express “ just ”, use 1 Express “ negative ”.
Value bits :
- The original code of a positive number 、 Inverse code 、 The complement is the same .
- The three representations of negative numbers are different .
Original code
The original code can be obtained by directly translating the numerical value into binary in the form of positive and negative numbers .
Inverse code
Change the sign bit of the original code , The reverse code can be obtained by inverting other bits in turn .
Complement code
Inverse code + 1 You can get the complement .
For integers : Data stored in memory is actually stored in the complement
In computer system , All values are represented and stored by complements . The reason lies in , Use complement , Symbol bits and value fields can be treated in a unified way ;
meanwhile , Addition and subtraction can also be handled in a unified way (CPU Only adders ) Besides , Complement code and original code are converted to each other , Its operation process is the same , No need for additional hardware circuits .
example :
int a = 20;
Decimal system :20
Binary system :
Original code :0000 0000 0000 0000 0000 0000 0001 0100( Positive numbers , Symbol bit 0)
because 20 Positive number , So the original 、 Inverse code 、 The complement is the same
Inverse code :0000 0000 0000 0000 0000 0000 0001 0100
Complement code :0000 0000 0000 0000 0000 0000 0001 0100( What is actually stored is the complement )
int a = -20;
Decimal system :-20
Binary system :
Original code :1000 0000 0000 0000 0000 0000 0001 0100( negative , Symbol bit 1)
because -20 It's a negative number , So follow the three code conversion rule for negative numbers
Inverse code :1111 1111 1111 1111 1111 1111 1110 1011( The sign bits remain the same , The other bits are reversed bit by bit )
Complement code :1111 1111 1111 1111 1111 1111 1110 1100( Inverse code +1)( What is actually stored is the complement )
There are two ways to convert a complement to an original code :
- According to the original code - - -> The order of complement is reversed : Complement code -1 Get the inverse , The reverse sign bit remains unchanged , Other bits are reversed to get the original code .
- Or according to the original code - - -> The complement sequence is pushing forward : First, the sign bit remains unchanged , The other bits are reversed bit by bit , And then again +1 You get the original code .( This also explains the conversion between complement and source code , Its operation process is the same , No need for additional hardware circuits .)
When two integers are added and subtracted :
// Add up
int a = 10;
int b = 20;
int c = a + b;
a Complement :0000 0000 0000 0000 0000 0000 0000 1010 //10
b Complement :0000 0000 0000 0000 0000 0000 0001 0100 //20
c Complement :0000 0000 0000 0000 0000 0000 0001 1110 //30
// Subtracting the
int a = 10;
int b = -20;
int c = a - b;// because CPU Only adders , So the actual implementation here is int c = a + (-b);
a Complement :0000 0000 0000 0000 0000 0000 0000 1010 //10
-b Complement :1111 1111 1111 1111 1111 1111 1110 1100 //-20
c Complement :1111 1111 1111 1111 1111 1111 1111 0110 //-10
// This explains why there is a complement
stay VS2019 View memory storage in

You can find , The order actually stored in memory is different from what we think . This involves the problem of the size end
Introduction to big and small end
What is big end 、 The small end :
Big end ( Storage ) Pattern , The low bit of data is stored in the high address of memory , And the high end of the data , Stored in a low address in memory ;
The small end ( Storage ) Pattern , The low bit of data is stored in the low address of memory , And the high end of the data , Stored in a high address in memory .
Why there are big end and small end :
Why are there big and small end patterns ? This is because in a computer system , We are in bytes , Each address corresponds to a byte , A byte is 8bit. But in C In language, except 8bit Of char outside , also 16bit Of short type ,32bit Of int Type and so on are greater than 8bit Data type of . in addition , For digits greater than 8 Bit processor , for example 16 Bits or 32 Bit processor , Because the register width is larger than one byte , So there must be a problem of how to arrange multiple bytes . So it leads to big end storage mode and small end storage mode .
for example : One
16bitOfshorttypex, The address in memory is0x0010,xThe value of is0x1122, that0x11For high byte ,0x22Is low byte . For big end storage mode , will0x11Put it in the low address , namely0x0010in ,0x22Put it in a high address , namely0x0011in . The small end model , Just the opposite . That we use a lotx86The structure is small end mode , andKEIL C51It's the big end mode . A great deal of ARM,DSP It's all small end mode . There are some ARM The processor can also choose the big end mode or the small end mode by the hardware .
Big and small end exercises :
Design a program to judge the byte order of the current machine
#include<stdio.h>
void CheckByteOrder()
{
int a = 1;
return *(char*)(&a);
}
int main()
{
if(CheckByteOrder())
{
printf(" The small end \n");
}
else
{
printf(" Big end \n");
}
return 0;
}
explain :
The difference between the big endian byte order and the small endian byte order is nothing more than the two order of high and low bytes and high and low addresses , And because we take the low address , So we only need to know whether the low address stores low bytes or high bytes . Because we only need to know the byte information at the low address , Then we need to isolate the low address , So cast the extracted address into type and dereference it .

practice
// What is the output result ?
#include <stdio.h>
int main()
{
char a = -1;
signed char b = -1;
unsigned char c = -1;
printf("%d %d %d\n", a, b, c);// The answers are -1、-1、255
return 0;
}
// explain :
-1 Original code 10000000 00000000 00000000 00000001
Inverse code 11111111 11111111 11111111 11111110
Complement code 11111111 11111111 11111111 11111111
Again because a yes char type , therefore a The complement of is 11111111
use %d To output char Type a, Let's first look at the data type for integer promotion , Look again at the sign bit
because a yes char type , Generally, it defaults to signed char, So raise the original sign bit
Complement code 11111111 11111111 11111111 11111111
The sign bit after integer promotion is 1, It's a negative number , Convert to the original code and then output
Inverse code 11111111 11111111 11111111 11111110
Original code 10000000 00000000 00000000 00000001
therefore a The output is -1, because b and a The same is signed char, So it also outputs -1
unsigned char c The difference from the first two is , When integer lifting ,c Look at the data type
It's a sign free , So promote 0
Complement code 00000000 00000000 00000000 11111111
And print %d Because the sign bit is 0, So I think it's a positive number , Print out the complement directly
therefore c Print out 255
// What is the output result ?
#include <stdio.h>
int main()
{
char a = -128;
printf("%u\n",a);// Output 4294967168
printf("%d\n",a);// Output -128
return 0;
}
// explain :
a Original code 10000000 00000000 00000000 10000000
Inverse code 11111111 11111111 11111111 01111111
Complement code 11111111 11111111 11111111 10000000
Again because a yes char type , therefore a The complement of is 10000000
When the output , First, integer promote according to the data type , because a yes char Consider signed
So lifting the sign bit is 1
Complement code 11111111 11111111 11111111 10000000
use %u When the output , Consider unsigned , Direct output complement , Output 4294967168
use %d When the output , Consider signed , First convert the bit source code , Then the output
Inverse code 11111111 11111111 11111111 01111111
Original code 10000000 00000000 00000000 10000000
The original output code is -128
Floating point storage in memory
Common floating point numbers ( decimal )
3.14159
1E10( Scientific enumeration ) 1.0 × 1 0 10 1.0×10^{10} 1.0×1010
The family of floating-point numbers includes :
float、double、long doubletype .The range represented by floating point numbers :float.h In the definition of .
int main()
{
int n = 9;
float* pFloat = (float*)&n;
printf("%d\n", n);
printf("%f\n", *pFloat);
*pFloat = 9.0f;
printf("%d\n", n);
printf("%f\n", *pFloat);
return 0;
}

The reason for this is that the storage rules and shaping of floating-point numbers in memory are completely different
Floating point storage rules
According to international standards IEEE( Institute of electrical and Electronic Engineering )754, Any binary floating point number V V V It can be expressed in the following form :
- ( − 1 ) S × M × 2 E (-1)^S×M×2^E (−1)S×M×2E
- ( − 1 ) S (-1)^S (−1)S The sign bit , When S = 0 S=0 S=0, V V V Is a positive number ; When S = 1 S=1 S=1, V V V It's a negative number .
- M M M Represents a significant number , 1 ⩽ M < 2 1\leqslant M<2 1⩽M<2
- 2 E 2^E 2E Indicates the index bit .
for instance :
Decimal 15.0 15.0 15.0, According to the scientific counting method, it will be written as 1.5 × 1 0 1 1.5×10^1 1.5×101
The binary 15.0 15.0 15.0 Namely 1111.0 1111.0 1111.0, According to the scientific counting method, it will be written as 1.111 × 2 3 1.111×2^3 1.111×23
that , According to the above V V V The format of , We can draw S = 0 , M = 1.111 , E = 3 S=0,M=1.111,E=3 S=0,M=1.111,E=3
The binary − 15.0 -15.0 −15.0 Namely − 1111.0 -1111.0 −1111.0, Write in scientific notation − 1.111 × 2 3 -1.111×2^3 −1.111×23
We can draw S = 1 , M = 1.111 , E = 3 S=1,M=1.111,E=3 S=1,M=1.111,E=3
IEEE 754 Regulations :
about 32 Floating point number of bits , The highest bit is the sign bit S S S, And then 8 Bits are exponents E E E, The rest 23 Bits are significant numbers M M M.

about 64 Floating point number of bits , The highest bit is the sign bit S S S, And then 11 Bits are exponents E E E, The rest 52 Bits are significant numbers M M M.

IEEE 754 For significant figures M And the index E, There are some special rules :
As I said before , 1 ⩽ M < 2 1\leqslant M <2 1⩽M<2, in other words , M M M It can be written. 1.xxxxxx In the form of , among xxxxxx Represents the fractional part .
IEEE 754 Regulations , Keep it in the computer M M M when , By default, the first digit of this number is always 1, So it can be discarded , Save only the back xxxxxx part . For example preservation 1.01 When , Save only 01, Wait until you read , Put the first 1 Add . The purpose of this is , Is to save one significant digit . With 32 For example, a floating-point number , Leave to M M M Only 23 position , Will come first 1 After giving up , It's equivalent to being able to save 24 Significant digits .
As for the index E, The situation is more complicated
First , E E E For an unsigned integer (unsigned int)
It means , If E E E by 8 position , Its value range is 0~255; If E E E by 11 position , Its value range is 0~2047. however , We know , In scientific counting E E E You can have negative numbers , therefore IEEE 754 Regulations , In memory E E E The true value of must be added with an intermediate number , about 8 Bit E E E, The middle number is 127; about 11 Bit E E E, The middle number is 1023. such as 2 10 2^{10} 210 Of E E E yes 10, So save it as 32 When floating-point numbers are in place , Must be saved as 10 + 127 = 137 10+127=137 10+127=137, namely 10001001.
then , Index E Fetching from memory can be further divided into three cases :
E Not all for 0 Or not all of them 1( General situation )
At this time , Floating point numbers are represented by this rule : The index E E E The calculated value of minus 127( or 1023), Get the real value , And then the significant number M M M Add the first 1.
such as :
When deposited ,0.5 The binary form of is 0.1, Since it is stipulated that the positive part must be 1, Move the decimal point one place to the right , Then for 1.0 × 2 − 1 1.0×2^{-1} 1.0×2−1, E E E by − 1 + 127 = 126 -1+127=126 −1+127=126, Expressed as 01111110, and $M$1.0 Remove the integer part and make it 0, A filling 0 To 23 position 00000000000000000000000, Then its binary representation is :
0 01111110 00000000000000000000000Take out the , Calculated value E E E
01111110subtract 127 Get the real value E = − 1 E=-1 E=−1, And significant numbers M M M00000000000000000000000add 1 Get the real value M = 1.0 M=1.0 M=1.0, And the sign bit S = 0 S=0 S=0
E E E All for 0( A special case )
At this time , Let the exponent of the floating point number E E E be equal to 1-127( perhaps 1-1023) That's the true value ,
Significant figures M M M No more first 1, It's reduced to 0.xxxxxx Decimals of . This is to show that ±0, And close to 0 A very small number of .
E E E All for 1( A special case )
At this time , If the significant number M M M All for 0, Express ± infinity ( The positive and negative depend on the sign S S S)
Explain the code at the beginning :
9 Complement code 00000000 00000000 00000000 00001001
use %d When printing , Just print out directly and change the complement code to 9
use %f When printing , according to IEEE 754 The provisions of the , Divide the memory into three areas , Revert to scientific counting
The three areas are :S=0,E=00000000,M=00000000000000000001001
and E For all 0, Then order E=-126,M Do not add the first 1
Scientific enumeration : V = ( − 1 ) S × M × 2 E V=(-1)^{S}×M×2^{E} V=(−1)S×M×2E namely V = ( − 1 ) 0 × 0.00000000000000000001001 × 2 − 126 V=(-1)^{0}×0.00000000000000000001001×2^{-126} V=(−1)0×0.00000000000000000001001×2−126 namely V = 1.001 × 2 − 146 V=1.001×2^{-146} V=1.001×2−146
Obviously , V V V It's a very small one, close to 0 Positive number of , So the decimal number is 0.000000.
Storage 9.0 when , To binary first 1001.0, And then turn it into scientific counting 1.001 × 2 3 1.001×2^{3} 1.001×23.
namely S = 0 , E = 3 , M = 1.001 S=0,E=3,M=1.001 S=0,E=3,M=1.001 When deposited , E = 3 + 127 = 130 E=3+127=130 E=3+127=130, M M M Discarding whole digits 1
Stored in memory is 0 10000010 00100000000000000000000
While using %d When printing , Look at the sign bit 0, Print out the complement directly, that is 1091567616
use %f When printing , How to save it, how to take it out and print it , still 9.000000
边栏推荐
- Halodoc's key experience in building Lakehouse using Apache Hudi
- 重构手法--Replace Conditional with Polymorphism
- Sword finger offer 24 Reverse linked list
- Is it safe to open futures online? Futures wonderful mobile phone account?
- Anaconda modify file save path
- EasyExcel 实现动态导入导出
- Idea start multiple services with the same set of code
- Will free price increases force young people back?
- Refactoring method --extract method
- 使用责任链模式重构原有的一段代码
猜你喜欢

Self taught scaffold - "data driven science and Engineering" by Steven L. Brunton (Chapter 5.0 - 5.4)

TiDB经验分享01

重构手法--Replace Conditional with Polymorphism

Why is the denominator of sample variance n-1 (unbiased estimation)?

指针的进阶(C语言超详细指针介绍)

Multithread concurrency

使用责任链模式重构原有的一段代码

Cmake record

在不同领域内自相关函数/自协方差函数含义辨析

Refactoring method --extract method
随机推荐
uwsgi loading shared libraries:libicui18n. so. 58 exception handling
The hcie Routing & switching test is postponed to December 31, 2022
Domestic cosmetics, lost 618
单条视频播放量破8000w,硬核做饭原来如此上头
C Looooops(拓展欧几里得)
Jupyter notebook configuring virtual environments
样本方差分母为什么是n-1(无偏估计)?
1px problem
Do not show browser running when using webdriver
Refactoring technique --extract class
TS 23.122
数据的存储(整型,浮点型超详细)
Tensorflow.js入门之mobilenet
关键字分类与第一个C程序
自学脚手架——“Data-Driven Science and Engineering” by steven L. brunton(Chapter 5.0 - 5.4)
Is long-term hotel rental a good business?
When the most successful and worst CEO dies, Sony still follows his old path
The era of bat and faang is over. Who will take over?
Modify Google Chrome cache location
do while for 等关键字