目录
1.数据类型的介绍
1.1C语言中的内置类型
数据类型 | 字节长度(sizeof) |
char | 1 |
short | 2 |
int | 4 |
long(long int) | 4/8 |
long long | 8 |
float | 4 |
double | 8 |
注:
1.对于long型数据的字节长度,规定sizeof(long)>= sizeof(int)
2.long long是C99标准中新引进的数据类型,是64位的长整型数据类型
3.C语言中有没有字符串类型?
答:C语言中没有原生的字符串类型,通过字符指针间接实现对字符串的操作
1.2类型的意义
- 类型决定了使用这个类型开辟内存空间的大小,大小决定我们可使用的空间
如上图,一个创建一个整型变量时,就会在内存中开辟4个字节的空间,一个字符型的数据在内存中开辟1个字节的空间,一个float型的数据在内存中开辟4个字节的空间,其他数据类型同理。当我们使用时也只能使用所开辟空间中的数据、
- 类型决定如何看待内存空间的视角
这点我们通过以下整型数据在内存中的存储来讲解
1.3类型的基本归类
- 整型家族
char unsigned char signed char
注:
- 为什么把字符型划分为整型? 因为字符的本质时ASCII码,是整型
- char是unsigned char还是signed char是标准未定义的,取决于编译器
int(signed int) unsigned int
注:
- 生活中有些数据是没有负数的,例如身高、体重等;但有些值是有负数的,例如温度等,所以产生了有符号整数和无符号整数
- 对于一个整型变量a,它在内存中占4个字节的长度,也就是32个比特位
- 浮点数家族
float double
注:
- 表示小数时使用浮点型
- float的精度低,存储的数值的范围较小;double的精度高,存储的数值的范围较大
- 构造类型
- 数组类型
- 结构体类型struct
- 枚举类型enum
- 联合类型union
- 指针类型
- 空类型:常用于函数的返回类型,函数参数,指针类型等
2.整型在内存中的存储
2.1数值的表示形式
数值的表示形式:二进制、八进制、十进制、十六进制
例:一个十进制数21
二进制形式:0b10101(前缀0b代表为二进制的写法)
八进制形式:025(前缀为0代表为八进制的写法)
十六进制形式:0x15(前缀为0x代表为十六进制的写法)
对于进制表示的序列,每一位数字都有其所占的权重,二进制序列的各位权重如上图,其他进制下同理。并且进制之间是可以相互转换的。
2.2原码、反码、补码
对于整数的二进制序列 也有三种表示形式:原码、反码、补码
原码:直接通过正负写出的二进制序列
反码:符号位不变,其它位按位取反
补码:反码加一
正整数的原码,反码,补码相同,负整数的原码直接写出,反码和补码通过上述步骤计算
例:int a=20;int b=-10;
20的原码/反码/补码:00000000 00000000 00000000 00010100
-10的原码:10000000 00000000 00000000 00001010
-10的反码:11111111 11111111 11111111 11110101
-10的补码:11111111 11111111 11111111 11110110
2.3整型的存储
我们继续以 int a=20;int b=-10为例
对于a的原码/反码/补码:0000 0000 0000 0000 0000 0000 0001 0100
这个二进制序列的每四位表示一位十六进制位
写成十六进制的形式:0x 00 00 00 14
-10的原码:1000 0000 0000 0000 0000 0000 0000 1010
十六进制:0x 80 00 00 0a
-10的反码:1111 1111 1111 1111 1111 1111 1111 0101
十六进制:0x ff ff ff f5
-10的补码:1111 1111 1111 1111 1111 1111 1111 0110
十六进制:0x ff ff ff f6
调试起来后,我们打开内存监视窗口,可以观察到:整型数据在内存中以二进制补码序列存储,并且是倒着存放的,这就是大小端问题,以下我们会进行讲解。
为什么使用补码存放,而不使用原码呢?
- 使用补码,可以将符号位和数值域统一处理
- 加法和减法可以统一处理
- 补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路
例:1+1----->1+(-1)
1的补码:00000000 00000000 00000000 00000001
-1的补码:11111111 11111111 11111111 11111111
补码相加后:1 00000000 00000000 00000000 00000000
我们知道整型是四个字节,32个比特位,所以这里超出的高位丢弃
结果是:00000000 00000000 00000000 00000000
最高位为0,是一个正整数,原码反码和补码相同,所以结果为0
对于补码我们是对原码除符号位取反再加一,通过逆运算,我们可以由补码得到原码,其实,补码除符号位取反再加一同样可以得到原码
-10的原码:10000000 00000000 00000000 00001010
-10的补码:11111111 11111111 11111111 11110110
补码除符号位取反:10000000 00000000 00000000 00001001
加一:10000000 00000000 00000000 00001010(原码)
3.大小端存储模式
在上述例子中,我们提到整型数据在内存中以二进制补码序列存储,并且是倒着存放的
实际上,整型数据在内存中是以字节为单位存储的
例如0x 11 22 33 44,其中,11为高字节序,44为低字节序
大端字节序存储模式:把一个数据的高位字节序的内容存放在低地址处,把低位字节序的内容存放在高地址处
小端字节序存储模式:把一个数据的高位字节序的内容存放在高地址处,把低位字节序的内容存放在低地址处
我们通过图展示
所以在VS中,倒着存是小端字节序存储方式
最后,我们浅做一个练习题:写一个程序判断当前机器是大端还是小端存储模式
分析:
以1为例:int a=1;
十六进制形式:0x 00 00 00 01
大端存储模式:00 00 00 01
小端存储模式:01 00 00 00
我们只需要判断第一个字节,为0则是大端存储模式,为1则是小端存储模式
如何只访问第一个字节的内容?
我们知道int型数据的字节长度是4byte,char型数据的字节长度是1byte
对于一个char型数据我们只能访问内存中一个字节
&a得到的是指向a的指针,(char*)&a 将指向a的指针强制类型转换为char*型,再解引用,这样我们就只能访问一个字节的空间了
具体函数实现代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int check_sys(int a)
{
return *(char*)&a;
}
int main()
{
int a = 1;
int ret = check_sys(a);
if (ret == 1)
printf("小端存储模式\n");
else
printf("大端存储模式\n");
return 0;
}