- 💖 作者简介:大家好,我是泽奀。
- 🏆 嵌入式领域新星创作者 ➕ 作者周榜: 31 ➕ 总排名: 4427 👑
- 📝 个人主页:泽奀的博客_CSDN博客
- 🎉 点赞 ➕ 评论 ➕ 收藏 == 养成习惯😜
- 📣 系列专栏:【C】系列_泽奀的博客-CSDN博客
- 💬 总结:希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🖊
- ✉️ 我们并非登上我们所选择的舞台,演出并非我们所选择的剧本 ♦
目录
🎉类型的意义:
✨C语言的类型分为
✨构造类型
✨指针类型
🎉空类型
✨函数的返回类型☮
✨函数的参数☪
🎉整形在内存当中的存储空间
🎆原码
🎆反码
🎆补码
🎃为什么在计算机中存储的是补码?
🧨大端小端介绍:
⚽判断大端小端
⚾代码演示
🥎自定义函数代码
🏀浮点型在内存当中的存储
🏐浮点数二进制补码
💎存储模式图:
🎋E不为全0也不为全1
🎋E全为0 (了解即可)
🎋E全为1 (了解即可)
使用这个类型开辟的内存空间的大小,从而大小也决定了范围。
基本类型:
它们是算术类型,包括两种类型:整数类型和浮点类型。枚举类型:
它们也是算术类型,被用来定义在程序中只能赋予其一定的离散整数值的变量。void 类型:
类型说明符 void 表明没有可用的值。派生类型:
它们包括:指针类型、数组类型、结构类型、共用体类型和函数类型。如何看清楚一个内存空间的视角,这个其实就是假设你
如何看待内存空间的视角:int的类型创建一个变量(a),占了4个字节, float类型创建一个变量(b),同样也只是占了仅仅4个字节的空间。但是给变量a的是格式符%d是一个整形,而给变量b的是格式符%f是一个单精度浮点型。
注意它们的存储的方式并不一样,大家可以在编译器上用调试内容一看就知道它们的内存是不同的
用 int a = 5;float b = 5.0; 用调试到内存那里就有了。
在这里其他类型我就不跟大家讲解了,就说说构造类型,以及指针类型吧。
- 数组类型:为什么说数组类型是构造类型呢?是因为假设 int arr[20],这样看是数组类型是吧。那么int [20] 是类型吧,那么我再进行一个改变int [10] 这个类型都在发生改变 那么如果你是不同的类型呢字符型,浮点型这样,所以数组也是一种自定义类型也是构造类型。
- 结构体类型:struct,成员类型在发生变化,那么它的结构体也在发生着变化。如果对结构体不了解的小伙伴们可以看看我文章里面有这个结构体的内容。
- 枚举类型:enum,这个是C语言的一个关键字,到时候会拿出写一篇给大家着重讲解这个枚举类型在C语言当中起到一个什么样子的作用。
- 联合体类型:union,这个也叫做是共用体,这个我们也现在不说。
- 指针的目的其实就是为了存放一个地址赋值给其中的变量,而指针的字节都是4个字节。
- 这样我们用一段代码让大家直观的看看是不是指针是4个字节,由于博主再前面跟大家讲过野指针的内容但是指针的内容还没有跟大家说,到时候博主也会写一篇有关于指针的内容,由此可见指针类型是一种特殊的类型。注意一下,指针的定义方式就是带*💨
#include<stdio.h> int main(void) { int a = 10; int* p = &a; //整形指针变量p接收a的地址 //这里数据类型全部定义成指针了-- 32位 4byte 64位 8byte printf("%d\n", sizeof(int*)); printf("%d\n", sizeof(short*)); printf("%d\n", sizeof(double*)); printf("%d\n", sizeof(char*)); }
- 一种特殊的返回类型,表示空函数,也就是没有返回值的函数。空类型(无类型) void 用于显示说明一个函数不返回任何值。还可以说明指向 void 类型的指针,说明以后,这个指针就可指向各种不同类型的数据对象💫
- void无传参,当你在定义程序的时候加入无传参的时候,虽说程序也会运行起来。但是会有waring提示就是不需要的参数
#include<stdio.h> void print() { printf("hello word\n"); } int main(void) { print(); }
#include<stdio.h> void print()//无参数的话进行传参也是可以的,但是这里没有所以我们C语言并不会进行接收 { printf("hello word\n"); } int main(void) { print(10);//在print函数当中给上参数10 }
想要了解这个内容的话,我用一段代码给大家演示下:
#include<stdio.h> int main(void) { int a = 5; int b = -3; }
a存储的结果
b存储的结果
- 大家发现了没有,这两个的存储结果是不一样的,接下来我就来告诉大家整形在内存当中是怎么存储的。
- 其实就是先要了解原码,反码,以及补码的概念。
计算机中有符号数(整形)有三种表示方法分别是:原码,反码以及补码。三种表示方法都有符号位和数值位两个部分,符号位是用0表示位"正",用1表示为"负",而数值位的三种表示方法各不相同。注:无符号的原码反码以及补码是相同的💨。
有符号数字是分为两种的一种叫做正数,另一种叫做是负数。在正数当中是相同的,然而在负数当中这三种的表达方式就不一样了💨
原码:-1
原码:1
......... 1001
0001
反码:-1
反码:1
..........1110
0001
补码:-1
补码:1
..........1111
0111
- 上面的是负数形式三种情况,...........这个是省略如果是整形前面32位数字,注意这里最高位是1,所以是负数的三种形式。
int a = 5;//4个字节 —— 32bit位 //0(最高位正数)0000000000000000000000000000101 int b = -3; //1(最高位负数)
其实还有一个办法可以算补码我一开始就是这样的:
1、假设是负数1的补码你先看成是负数1原码的数字—10001(注意这里的最高位是1,是负数)
2、再直接反码注意最高位不用反码了——11110
3、最关键的一步就是补码了切记补码最后一位加1是1就往前面一位数字进1,结果就是——11111
当然这个是笨办法,如果不能理解的话用这个也是可以的我一开始就是这样😂
将你的符号位不变,也就是最高位不变,其次再依次的按位取反,得到反码。
比如 int = - 10;的反码就是—
补码就是 反码+1 就能够得到补码,注意是前提是要反码加一💨
还是 比如 int = - 10;的补码就是—
这里注意一下是满2进1,不要弄错了~!
如果它是正数的话:原码、补码以及反码都是相同的!
是负数的话就是我上面说的这样!对于整形来说存放的都是补码,切记!
一个字节=8个bit
在计算机的系统当中,数值都是用补码来表示存储的。原因在于,使用补码,可以将符号位和数值域进行统一的处理;同时,加法和减法当中用补码也可以进行统一的处理(CPU当中只有加法器),此外,尤其是补码与原码的运算过程是可以进行相互转换的!
那么我着重的跟大家说说这个加法器吧,这个加法器其实就是当中CPU运用的加法运算,好接下来我给大家举个例子比如说:1 - 1 那你要转换成加法器怎么办呢?其实很简单只需要:1 + (-1) 就可以了,那么如果你现在要用原码来算呢?
1的原码: 00000000000000000000000000000001
-1的原码: 000000000000000000001
结果: 000000000000000000010 所以,1+(-1) = -2吗?答案显然不是的
好!那现在如果我们用补码来算一下呢
1的补码: 0000 0000 0000 0000 0000 0000 0000 0001
-1的补码: 1111 1111 1111 1111 1111 1111 1111 1111 1111
结果: 1 0000 0000 0000 0000 0000 0000 0000 0000
但是:我们整形当中只能存储的是32位,所以留下的是0,所以用补码进行运算的时候我们是可以算出一个正确的结过的,想到这,我真的觉得当时创作出这个算法的人估计是个神仙吧😯,乘法就是^几次放就加多少,也有可能是转换成某一个运算吧。但是原理都是一样的就是我只要有加法,这些事情我都可以办到。
用代码实现判断大端小端:
解体思路:一个数字a,存储在内存当中,假设这个a是20的话,在不知情的情况下,不知道当前是大端还是小端的存储。但是,可以推测是不是大端还是小端,就像上面内容所说的那样。我们可以观察它们的第一个字节,就比如说:
#include<stdio.h> int main(void) { int a = 1; char *p = (char*)&a; if (*p == 1) { printf("小端\n"); } else { printf("大端\n"); } return 0; }
运行结果🖊
小端
#include<stdio.h> int Testing() { int a = 1; char * pb = (char*)&a; if (*pb == 1) return 1; else return 0; } int main(void) { int ret = Testing(); //返回1代表的是小端,返回0代表的是大端 if (ret == 1) { printf("小端\n"); } else { printf("大端\n"); } return 0; }
在这里说下指针类型的意义
常见的浮点数:
浮点数包括:
记数法实例:
- 第1列是一般记数法;
- 第2列是科学记数法;
- 第3列是指数记数法(或称为e记数法);
- 这是科学记数法在计算机中的写法,e后面的数字代表10的指数;
接下来给大家看一个代码:
#include <stdio.h> int main(void) { int n = 9; float *pFloat = (float *)&n; printf("*pFloat的值为:%d\n",n); printf("*pFloat的值为:%lf\n", *pFloat); *pFloat = 9.0; printf("num的值:%d\n", n); printf("*pFloat的值为:%lf\n",*pFloat); return 0; }
- 从上述代码可以看出:浮点型和整形的内存的存储的形式不一样!
- 可能会有些小伙伴有些疑问,为什么第二行运行结果的*pFloat的答案是:0.000000,还有第三行的num的运行结果是:,我觉得因该是 9.000000 和 9啊。好,别着急现在就来说说为什么!
- 打印:0.000000是因为:整形的形式放进去的时候在以浮点数的形式往后拿的话,拿不到我们期望的一个结果,那是不是可以说明整形的存储结果和浮点型的存储的方式是不一样的,如果一样那就是一样的结果了✨
- 打印:是因为:*pFloat我们是用浮点数的形式存放进去的,然后以n的正数形式在拿的时候是整数的形式拿出来的,拿出来了一个错误的值✨
- 从这里就说明了整形的存储方式和浮点型的存储方它们是由区别的💨
- 1001
- 1001.0
- 1.001 * 2 ^ 3 —— 注意:这个是二进制
- (-1) ^ 0 * 1.001 * 2 ^ 3 = (-1)^ M * 2 ^ E
- 0 000000000000 —— E = 3 + 127 = 130
- 当成原码直接打印的就是我们上面说的数字
- 这样就可以确定的是 — s = 0 ,M = 1.001 ,E = 3 ,注意M = 1.001 实际上是:0001
- 0.5
- 0.1 — 注意:这个是二进制当中的 -1 对于小数点来说后面的第一位数,是2的负一次方就是0.5
- 1.0 * 2 ^ -1 —— 转换成科学计数法
- (-1 ^ 0) * 1.0 * 2 ^ -1 —— 注意:指数E为一个无符号数字来看待的
- s = 0,M = 1.0,E = -1
- 对于八位的E来说是,这个中间的数是:127,对于十一位的E来说是,这个中间数是1023,其实就是如果你的E是负数的话,就拿-1来举个例子 八位的就是:-1+127 = 126,11位的就是:-1+1023 = 1022
- 浮点数 5.5
- 101.1 // 前面是101按照8421码来,后面的就是2的负一次方 等于 0.5
- (-1) ^ 0 * 1.001 * 2 ^ 2
- s = 0 ,M = 1.011 ,E = 2 (E+127=129)
- 0100 0000 1011 0000 0000 0000 0000 0000 ——这里E的存储是129,E的值还是129-127=2,如果你是double的数字那么这里要减去1023才能的到真实的E的值
- 0x40B00000 —— 转换出来的二进制转换十六进制数字
- 调试当中内存的结果:
这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第一位的1,而是为了还原位0.xxxxxx的小数,这样做是为了表示±0,以及接近于0的很小数字。
这时,如果有效数字M全为0,表示±无穷打(正负取决于符号位s)