数据的存储:
一个数据被创建好之后,根据类型的不同,所开辟的空间大小是不一样的。
数据有内置类型和自定义类型之分。
整形家族:
1.char 这里为什么说字符类型也属于整形:因为内存中存储字符存放的是它的ASII值,比如字符a存储的时候,存放的是ASII值,即97,因此,字符的本质也是整形。
unsigned char 无符号:1个字节,8个比特位,最高位不是符号位,是有效位。可以表示的是0-255;
signed char:有符号,例如:01010001:最高位被做当作符号位,如果为1则为负数。
2.short:()可以省略。
- unsigned short(int)
- signed short(int)
3.int
- unsigned int
- signed int
4.long
- unsigned long (int)
- signed long(int)
浮点型家族
1.float
2.double
构造类型
1.数组类型:例如int a[10]={0},去掉数组名,即是数组的类型:int[10];int[10]和int[5]是不一样的,所以数组可以认为是构造类型。
2.结构体类型
3.枚举类型
4.联合体(共用体)类型
指针类型
指针类型主要是用来存储变量的地址。
空类型
void 表示空类型(无类型),返回值为空。
对于void *:是不可以解引用的;
整型在数据中的存储
我们知道计算机中整形有三种表示方式:原码,补码和反码。计算机中,数据以补码的形式存储。
为什么要以补码的形式存储?
使用补码可以将符号位和数值域统一处理,加法和减法也可以统一处理,此外补码和源码相互转换,过程是相同的,不需要额外的硬件电路。
-
1.无符号的整型:原码=反码=补码;
-
2.有符号的整数:包含正数和负数;
-
正数的存储
int a =10;
原码=反码=补码。
原码:符号位为0,其他为数值位翻译为二进制即可。
例如:a的原码为0x 00 00 00 0A;
-
负数的存储
int b=-20;
b:原码:1000_0000_0000_0000_0000_0000_0001_0100
b:反码:1111_1111 _ 1111_1111_1111_ 1111_1110 1010
b补码:1111_1111 _ 1111_1111_1111 1111_1110 _1011;
负数的原码:最高位为符号位取1,数值位翻译成二进制即可。
负数的反码:最高位不变,其他位按位取反。
负数的补码:符号位不变,反码+1即得到了补码。
-
大小端存储模式
每一个内存单元有相应的地址,相当于门牌号一样(以字节为单位进行编号)。看到前面的数据存储方式,不知道你有没有疑惑,为什么10和-20的存储方式如图所示呢,。
因为计算机中:每一个地址单元对应着一个字节,对于不同的数据类型它占据的字节是不一样的,比如int:占据4个字节,所以就有可能有两者存储方式。
内存单元都有编号:编号小的称为低地址,编号大的称为高地址
大端存储模式:数据的低位存储在内存的高地址中。
小端存储模式: 数据的低位存储在内存的低地址中。如图所示:0a为低位,存储在低地址处。
大端和小端存储又称为数据在内存中存储的字节顺序。又称为大端字节序和小端字节序
那么我们是否可以写一个程序来判断当前机器的字节序列?(即是大端还是小端存储呢)
int check_sys()
{
int a = 1;
char *p = (char)&a;
//&a本来是int*,强制转换成char*类型,即解引用可以访问1个字节
//指针类型决定了指针解引用操作符能访问几个字节,char*p,*p,访问1个字节;int*p,*p,访问4个字节。
//指针类型决定了指针加1,减一跳过几个字节,整型指针,p+1,跳过4个字节,char*型,跳过1个字节。
//返回1,小端;返回0,大端;
return *p;
}
整型提升:
A character, a short integer, or an integer bit-field, all either signed or not, or an object of enumeration type, may be used in an expression wherever an integer maybe used. If an int can represent all the values of the original type, then the value is converted to int; otherwise the value is converted to unsigned int. This process is called integral promotion."
翻译过来就是:表达式中可以使用整数的地方,就可以使用枚举类型,或有符号或无符号的字符、短整数、整数位域。如果一个int可以表示上述类型,则该值被转化为int类型的值;否则,该值被转化为unsigned int类型的值。这一过程被称作integral promotion。
整形提升是按照变量的数据类型的符号位来提升的
也就是计算的时候:都要转换为int类型;
整型提升的意义:
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。
unsigned char 和 char 可以存储的整型大小
char :有符号char型:-128到127;
以补码来看:
00000000
00000001
00000010
…
011111111 这里代表的是127;补码=反码=原码;因为是正数
10000000 这里特殊一点:规定是-128;所以127+1=-128;
假设-128用 9位bit位表示,即110000000,故数值位为10000000
10000001 反码:10000000;原码:11111111:代表的是-127;
10000010
…
111111111 反码:111111110,原码:10000001:代表的是-1;
unsigned char:0到255;原码=反码=补码;
几道容易做错的题目
int main()
{
char a = 128;
printf("%u\n",a);
return 0;
}
计算机中,是以补码的形式进行存储整型变量的。
- 先写出补码形式:128的补码为00000000_00000000_00000000_10000000
- 因为1个char型只能存储8个bit位。所以a里面存储的数据为10000000。
- 因为要被打印成整型变量,会发生整型提升。整型提升是看原变量的最高位即符号位是0还是1;此时符号位为1,整型提升之后的结果为:11111111_11111111_11111111_10000000
3 .因为打印的时候是以%u的形式打印的,所以补码等于反码等于原码,计算之后的结果为4294967168。
这里需要注意我们打印出来,可以看到的数字都是以原码的形式表示出来的,因此如果是有符号数的话,补码需要转换成原码。
#include <stdio.h>
int main()
{
char a = -128;
printf("%u\n",a);
return 0;
}
-128:
补码:11111111_11111111_11111111_10000000。
小技巧:高位都为111111111;
截断之后:10000000;符号位1;
整型提升之后为:11111111_11111111_11111111_10000000-补码
因为是无符号整型:所以补码等于反码等于原码:结果和上面的相同。