目录
类型的基本归类
整型:
char
unsigned char
signed char
short
unsigned short [int]
signed short [int]
int
unsigned int
signed int
long
unsigned long [int]
signed long [int]
有一些数值存在正负之分,而有一些没有正负之分,只有正数
所以在C语言中,我们可以使用 signed (有符号类型)unsigned(无符号类型)前缀来修饰变量
但是一般定义变量会默认省略 signed
例如: signed int = int signed long = long
但是signed char 是否等同于 char,一般取决于编译器(Visual Studio是相等的)
值得一提的是:
字符存储和表示的时候本质上使用的是ASCII码值,ASCII码值是整数,所以字符类型归类到整型
浮点数 :
float
double
构造类型(自定义类型):
> 数组类型
> 结构体类型 struct
> 枚举类型 enum
> 联合类型 union
指针类型
int *pi;
char *pc;
float* pf;
void* pv;
空类型:
void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型
整形在内存中的存储
一个变量的创建是要在内存中开辟空间的。空间的大小是根据不同的类型而决定的
比如
int a = 20;
int b = -10;
我们知道为 a 分配四个字节的空间
那如何存储?
对于整形来说:数据存放内存中其实存放的是补码
原因是:
在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统 一处理; 同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程 是相同的,不需要额外的硬件电路
如何理解,下面举个例子
int a = 1;
int b = 1;
a - b = 1 - 1;
但是由于CPU只有加法器,所以亦可以换为1 + (-1)
对于1而言他的补码为:00000000000000000000000000000001
对于-1而言他的补码为:1111111111111111111111111111111111111
相加即为:00000000000000000000000000000000
最高位丢失
也就是0
但是此处如果使用原码,则无法达到效果,这也是为什么存放的是补码
下面观察一下变量创建后在内存的样子:
对于10而言,他的补码形式为:00000000000000000000000000001010
对于20而言,他的补码形式为:00000000000000000000000000010100
将二进制补码表示形式换做16进制表示形式即为
10:00 00 00 0a 20:00 00 00 14
但是我们发现顺序有点不对劲
图上是 0a 00 00 00 和 14 00 00 00 的存放方式
这是又为什么?
这就需要提到下一个概念
大小端
下面看几个容易误解人的代码
unsigned int i;
for(i = 9; i >= 0; i--)
{
printf("%u\n",i);
}
对于这个代码而言,由于i是无符号整型
当循环走到i为0减1时,由于他为无符号整数,i不会出现小于0的情况,所以这是一个死循环
而且由于i-1本应为-1,在内存本应该为10000000000000000000000000000000
但是无符号,则最高位不算做符号位,所以此时以%u的方式打印0之后
会打印4,294,967,295
int main()
{
char a[1000];
int i;
for(i=0; i<1000; i++)
{
a[i] = -1-i;
}
printf("%d",strlen(a));
return 0;
}
对于这个代码而言,数组a是存放char类型的数组,但是存放的是整型
由于char类型的取值范围是-128 ~ 127,存放整型会发生截断,只记录1个字节空间的数据(8bit)
当for循环给char数组赋值到-128时,下一次赋值时,会令值变为127(在char类型角度看)
通过下图来理解:
unsigned char i = 0;
int main()
{
for(i = 0;i<=255;i++)
{
printf("hello world\n");
}
return 0;
}
对于这个代码,创建了一个全局 unsigned char 类型变量,取值范围为0~255
由于i无法超过255,所以该循环为死循环