Fixed-point and floating-point numbers
All mentioned in this article are based on intel x86Cpu, and the development environment is based on windows 10 + vs2019. This blog requires readers to understand the conversion between decimal, hexadecimal, and binary. The conversion process will not be introduced in the article. You need to understand the detailed process to find relevant information.
First, we briefly introduce the basic knowledge of data storage in computers. The specific content is described in detail in the university course "Principles of Computer Organization". There are two forms of data storage in computers, one is to store in fixed-point numbers, that is, char, short, int, long, longlong in C/C++, and the other is to store in floating-point numbers, that is, C/C++. Float, double in.
The storage principle of char, short, int, long, and longlong in fixed-point numbers is the same, but the length is different, so we choose the int type to introduce in detail, and the principle of float and double in floating-point numbers is the same, we choose float to introduce in detail.
Among them, fixed-point numbers and floating-point numbers are both the highest bit indicating the sign bit (0 indicates a positive number, 1 indicates a negative number) and the remaining bits indicate the value, and the byte is a flashback (little-endian mode), which means that the high byte is on the left and the low word The section is on the right.
Fixed point
The fixed-point number is relatively simple. The computer stores the real value. The computer uses 4 bytes (32 bits) to store int variables. For example: int value = 1; then the value is converted into binary 0000 0000 0000 0000 0000 0000 0000 0001 for the convenience of writing. Written in hexadecimal form as 00 00 00 01. Since the computer is flashback storage, the computer is stored as 01 00 00 00.
Floating point
The following introduces floating-point number float storage. The float storage standard in C/C++ is based on IEEE754. The specific content is a value, which can be expressed in scientific notation, that is, it can be written as:
A * 2^n
其中A为尾数,2为底数,n为指数。
Since the base is 2, all A is greater than 1 and less than 2, that is, it can be written as 1.xxxx*2 to the power of n. Therefore, in order to save space, the computer can not store the integer part of 1, because all floating-point numbers have When we convert the 1 we can count that 1 in. n can be positive or negative (127 needs to be added).
The storage of floating-point numbers consists of sign + exponent + fraction.
Types of | Sign bit | index | mantissa |
---|---|---|---|
Float | 1 place (31st place) | 8 digits (23~30 digits) | 23 digits (0~22 digits) |
Double | 1st place (63rd place) | 11th place (52nd to 62nd place) | 52 digits (0~51 digits) |
For example: float value = 12.5; then
Decimal to binary method: the integer part is divided by 2 and the decimal part is multiplied by 2
float computer storage (little-endian mode) ie 00 00 48 41
double computer storage (little endian mode) i.e. 00 00 00 00 00 00 29 40
View memory verification results
#include<stdio.h>
int main()
{
float a = 12.5;
float* p = &a;
double b = 12.5;
double* pb = &b;
printf("%d\n", a);
printf("%d\n", (int)a);
printf("%d\n", *(int*)&a);
return 0;
}
Check the addresses of variables a and b through breakpoints, and use the memory viewer to check the corresponding memory through the addresses to verify
When VS2019 runs to the breakpoint, the menu debug->window->memory->memory 1
Memory is not deceiving, so the results are verified correctly
Big end little end
Big-endian mode :指数据的高字节保存在内存的低地址
For example: the storage order of 12345 (0x3039) is 0x30、0x39
Little endian mode :指数据的高字节保存在内存的高地址
For example: the storage order of 12345 (0x3039) is 0x39、0x30
Judge the big end
method one:
#include<stdio.h>
int main(int argc, char *argv[])
{
int i = 0x12345678;
char c = i;
if (c == 0x78)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
Method Two:
#include<stdio.h>
int main(void)
{
int a = 0x12345678;
char *p = (char *)&a;
if (0x78 == *p)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
Method three:
#include<stdio.h>
typedef union NODE
{
int i;
char c;
}Node;
int main(int argc, char *argv[])
{
Node node;
node.i = 0x12345678;
if (0x78 == node.c)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
Question 4 of the previous issue
#include<stdio.h>
int main()
{
float a = 12.5;
printf("%d\n", a);
printf("%d\n", (int)a);
printf("%d\n", *(int*)&a);
return 0;
}
- printf("%d\n", a);
Because printf does not match the type, it will directly convert float to double, double 8 bytes, and 12.5f to hexadecimal: 0x40290000 00000000
The value stored in the computer (in little endian mode) is: 00 00 00 00 00 00 29 40
Our %d requirement is a 4-byte int. For the double memory layout, we can see that the first four bytes are 00, so the output is naturally 0.
- printf("%d\n", (int)a);
Float is forced to be converted to int, the decimal part is omitted, and all are 12
- printf("%d\n", (int)&a);
Float 4 bytes, 12.5f converted into binary is: 01000001010010000000000000000000, hexadecimal is: 0x41480000, decimal is: 1095237632.
Question 10 of the previous issue
Topic review:
#include<stdio.h>
int main()
{
int a = 3, b = 5;
printf(&a["Ya!Hello! how is this? %s\n"], &b["junk/super"]);
//等价printf("Hello! how is this? %s\n", "super");
printf(&a["WHAT%c%c%c %c%c %c !\n"], 1["this"], 2["beauty"], 0["tool"], 0["is"], 3["sensitive"], 4["CCCCCC"]);
return0;
}
Alternative usage of pointers:
char arr[20] = "hello world";
printf("%s\n", arr); //从&arr[0]地址处开始读取字符串到'\n'结束 输出hello world
printf("%s\n", &arr[6]); //从&arr[6]地址处开始读取字符串到'\n'结束 输出world
printf("%s\n", &6[arr]); //从&arr[6]地址处开始读取字符串到'\n'结束 输出world
arr[i] is actually *(arr+i) which is *(i+arr), which belongs to the grammatical rules, but it is used less.
printf(&a["Ya!Hello! how is this? %s\n"], &b["junk/super"]);
//等价printf("Hello! how is this? %s\n", "super");
Here "Ya! Hello! how is this? %s\n" is a string stored in the constant area
char* p = "Ya!Hello! how is this? %s\n";
char* p1 = "junk/super";
printf(&a[p], &b[p1]);
printf(&p[3], &p1[5]);
The numbers 3 and 5 here are the offset of the address