目录
前言
一,VS的知识储备
二,有趣的scanf()读取
三,数据的存储 引言
四,整数存储
五,小数存储
总结
前言
这里将深入计算机,看计算机是如何进行数据的存储的,怎么在计算机里面筑巢
为什么会有debug和release两个玩意,太可恶了有时候bebug不行,release可以有时候又反之,知识人性的考研还是计算机的腐败
神奇的scanf在我编写程序与我摩擦出了怎么样的火花
大小端又是一个什么东西,究竟会为什么会改变我对存储的认知
一,VS的知识储备
1,debug和release的区别
两者的主要区别是在于编译的方式,优化等级,预处理器宏定义和运行时库
debug模式主要运用于调试,适合在开发阶段
release模式主要用于优化代码,提高执行效率,适用发布阶段1,编译方式
debug模式下编译器会生成的可执行文件中包含调试信息
release模式下编译器会开启多种优化选项,以提高程序的执行效率2,优化等级
bebug模式会关掉各种优化选项,以便调试程序
release模式会开启各种优化选项,以提高程序的执行效率3,预处理器的宏定义
debug模式下通常会定义一些预处理器,以便调试程序,而release则不需要
常用的预处理器宏
为了区分这两种模式,通常会定义一些预处理器宏。例如:
在 Debug 模式 下,可能会定义
_DEBUG
或DEBUG
宏在 Release 模式 下,这些宏通常不会被定义
4,运行时库不一样
debug模式下运行时,库通常是多线程调试版本,而release为多线程,非调试版本,这是也为了减少可执行文件的大小,提高效率
Debug 模式(调试模式)
运行时库:通常是多线程调试版本(如
/MTd
或/MDd
)。这些库包含了调试信息和额外的错误检测机制,例如内存分配检查、缓冲区溢出检测等特点:
包含调试符号信息,便于调试工具加载和使用
生成的可执行文件体积较大,运行速度较慢,但能提供丰富的调试支持
通常会生成
.pdb
文件,用于存储调试信息Release 模式(发布模式)
运行时库:通常是多线程非调试版本(如
/MT
或/MD
)。这些库不包含调试信息,专注于性能优化特点:
不包含调试符号信息,减少了可执行文件的体积
优化了代码执行效率,提升了程序的运行速度
更适合最终用户使用,因为其体积小、运行速度快
2,X86和X64
X86是32位的X86架构,此架构使用大多数旧的32位windows操作系统和处理器,如果你的应用程序在此平台运行,要选着这个X86架构
X64是64位的X64架构,此架构适用支持64位操作系统于处理器的计算机,X64无法在32位操作系统运型,但是可以又更大空间进行操作
32位和64位架构的区别:
地址空间:64位架构支持更大的地址空间
寄存器数量和宽度:64位架构有更多的寄存器,寄存器宽度更大
指令集:64位架构支持更复杂的指令集
性能和效率:64位架构通常更适合高性能计算和大数据处理
栈空间:64位系统可以支持更大的栈空间,但默认的栈大小并不一定比32位系统大
二,有趣的scanf()读取
我在使用scanf的时候遇到了这个问题
我想正常的输入一个带有空格的字符串,但是最后打印出来只有一个I,我的LOVE YOU没有了,是因为scanf扫描到I后面的空格的时候就忽略了后面的LOVE YOU
scanf() 在读取字符串得时遇到空白字符串(空格,制表符和换行符)时会停止读取,并将剩下的字符(包括换行字符)留在stdin输入流里面(不是键盘缓冲区)#include <stdio.h> #include <windows.h> int main(void){ char str[80], str1[80], str2[80]; scanf("%s",str);/*此处输入:I love you!*/ printf("%s\n",str); Sleep(5000);/*这里等待5秒,告诉你程序运行到什么地方*/ scanf("%s",str1);/*这两句无需你再输入,是对stdin流再扫描*/ scanf("%s",str2);/*这两句无需你再输入,是对stdin流再扫描*/ printf("%s\n",str1); printf("%s\n",str2); return 0; }
由此可知残留的信息是保存在stdin输入流里面,而不是缓冲区里面
三,数据的存储 引言
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> int main() { int i = 0; int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; for (int i = 0;i < 12;i++) { arr[i] = 0; printf("hehe\n"); return 0; } return 0; }
我们这个代码其实是一个错误的代码,有数组溢出的风险,但是我们分别debug和release去运行
debug的
release反而相反
存储
C99(1999年推出的C语言第三代)里面有long long为8个字节
类型
long为4个字节或者8个字节>=int(在X86平台下为4字节,在X64平台下为4字节)
short为2字节
类型的意义:1,开辟内存空间的大小 2,看待内存空间的大小整形家族
字符型本质就是ASCII码,所以划分到整形
char有三种类型,char!=signed char(不一定)这个取决于编译器,可能是signed char或者unsigned char
int有两种类型,int=signed intsigned和unsigned的意义
在现实生活中,如果没有负数(如:身高,体重,…),有负数(温度,体温…)
有符号的正数范围会减小,无符号的正数的分为会变大其他类型
自定义类型:数组,枚举,联合体,结构体
指针类型:空类型void*
void作为形参的时候,只是起说明作用
四,整数存储
进制的快速判断为多少的技巧
我看这个图不难的出里面其中的规律,每往前面前进对应的数字的次方都是+1,然后最后利用数字与这些数字相乘即可
进制的三种类型
三种类型:1,原码 2,补码 3,反码
正数:三种类型都是相同的
负数:反码:除符号位不变,其余的按位取反
补码:在反码的基础上加上1
内存其实存储的是二进制,但是在显示器上面显示的为16进制,并且存储的为二进制的补码
为什么要用补码而不是原码呢?
我们以1-1为例子
根据上面这个图,应该很快就可以理解了
大小端
如int a = 20 0x 11 22 33 44 int b = -10 0x 55 66 77 88
大端:高位放高端 小端:地位放高端
总:大端正常,小端反常
很多编译器都是以小端的形式存储的
五,小数存储
1E10为1.0*10^10#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> int main() { int n = 9; float* pfloat = (float*)&n; printf("%d\n", n); printf("%f\n", *pfloat); *pfloat = 9.0; printf("%d\n", n); printf("%f\n", *pfloat); }
当你看到这个答案,肯定会以为是9,9.000000,9,9.000000
当然答案并不是这个
答案是这个,为什么呢?接下来,小数的存储会给你答案
浮点数的存储规则:
根据IEEE规定,任意一个二进制浮点数V可以表示下面的形式
V=(-1)^s*M*2^E
(-1)^s为符号位 s=0为正数,s=1为正数
M为有效数字 >=1 <2
2^E表示指数
这里有两个例子,首先二进制表示这个浮点数,小数点的左边跟正数一模一样,小数点的右边也跟正数差不多,只不过为负的次方
为什么有的数字不精确,这就可以得出答案了,因为后面就是2^-1,2^-2……这样没办法对于一些数字的精确
计算机是对于ME有相关规定的
M
根据IEEE规定,在计算机内部保存M的时候,默认这个M为1的,如果只有一个M的话可以省掉不屑,如保存1.01的时候,可以写成.01
目的:提高精度,舍掉1存1,则从23位数跳到了24位数E
unsigned int类型
但E也有可能为-1
0.5---0.1---1.0*2^-1---(-1)^0*1.0*2^-1
由于出现了-1,这个规则就需要完善
则就出现了中间值这个概念(以0.5为例子)
(浮点类型为1023,整形类型为127)
float---E(真实值)+127(中间值)---126---存储
double---E(真实值)+1023(中间值)---1022---存储
例子
5.5---(-1)^0*1.011*2^2
E1=E+127=129---存储
浮点数的拿出
E不全为0或者不全为1时
E-127,同时M前面加1,5.5为例子
这个就是在011前面加1.,然后后面这个次方2就是减去127即可
E全为0,直接为1-127或者1-1023就是真实值,表示无穷小
E全为1,这里M的有效数字为0,表示无穷大
E0.000……表示+-0无限接近0的数字
总结
1,debug和release
一个是运用到代码开发,一个运用到发布
debug是用于改进代码,会爆出相应的错误,但是包含的库文件就会更加庞大
release是用于优化代码,会自动优化代码,包含的库文件文件会比较小,但是不会报错,不适用代码开发
2,scanf()
遇到空格等字符会进行停止扫面,剩下的部分在stdin流里面,而不是键盘输入流
3,整数的存储
整形的家族是包括char类型的,而且要知道无符号和有符号的意义
整形的存储有三个形式,原码,反码,补码
计算机存储的补码,原因是可以便于进行计算,计算之后直接就是答案了
4,浮点数的存储
(-1)^s*M*2^E
首先我们利用二进制,小数点左边就是整数一样的二进制形式,右边就是次方为相反数,这个就是小数不可以精确的原因了
M规则:可以把第一个1省略掉,这样就可以从23位到24位,扩大范围
S规则:由于位unsigned int类型,所以就有了中间值这个概念,float:127 double:1023
浮点数存储位第一位:s值,后8位:表示M,剩下的就是小数点后面的数字了,然后再后面补0就好了