C语言的类型
1.内置类型
char
short
int long float
double
2.自定义类型(构造类型)
类型的意义:
1. 使用这个类型开辟内存空间的大小(大小决定了使用范围)。
2. 如何看待内存空间的视角。
int main()
{
int a=10;//4 0a 00 00 00
float f=10.0;//4 00 00 20 41
return 0;
}
整形家族
char//char在内存中存储的是acs码值,属于整形,C语言标准并没有确定有误符号,取决于编译器,大部分默认是signed char
unsigned char//有符号的char指的是在char所表示的一个字节(8个二进制位)中,无符号表示(11111111表示255),可以表示0~255
signed char//有符号的char指的是在char所表示的一个字节(8个二进制位)中,最高位表示符号位,1表示负数,0表示正数(11111111表示127),可以表示-128~127
short
unsigned short [int]//int可以省略也可以写上
signed short [int]
int
unsigned int
signed int
long
unsigned long [int]//int可以省略也可以写上
signed long [int]
浮点型家族
float
double
long double
构造类型(自定义类型)
> 数组类型
> 结构体类型 struct
> 枚举类型 enum
> 联合类型 union
指针类型
大小恒定,都是四个或八个字节
int *pi;
char *pc;
float* pf;
void* pv;//无具体类型的指针
空类型
void 表示空类型(无类型) ,没有返回值
通常应用于函数的返回类型、函数的参数、指针类型。
void test()//如果括号中没有写任何内容,可以传参,也可以不传参,如果想要规定函数明确不需要传递参数,可以在括号中加上void
{
printf("呵呵\n");
}
int main()
{
test(100);
return 0;
}
int main()
{
int a=20;//14 00 00 00
//00000000 00000000 00000000 00010100原码
//00000000 00000000 00000000 00010100反码
//00000000 00000000 00000000 00010100补码
//0X 00 00 00 14转换为十六进制位
int b=-10;//f6 ff ff ff
//10000000 00000000 00000000 00001010原码
//11111111 11111111 11111111 11110101反码
//11111111 11111111 11111111 11110110补码
//0X ff ff ff f6转换为十六进制位
return 0;
}
计算机中的整形有三种表示方法,即原码、反码和补码。
三种表示方法均有符号位(最高位)和数值位两部分,符号位都是用0表示“正”,用1表示“负”,
而数值位 负整数的三种表示方法各不相同。
原码
直接将数字按照正负数的形式翻译成二进制就可以。
反码
将原码的符号位不变,其他位依次按位取反就可以得到了。
补码
反码+1就得到补码。
//无符号数的原码,反码,补码是相同的。
//正整数的原码,反码,补码,相同
//内存中存储一个整数存储的是它的二进制序列的补码
对于整形来说:数据存放内存中其实存放的是补码。 为什么呢?
在计算机系统中,数值一律用补码来表示和存储。
原因在于,使用补码,可以将符号位和数值域统 一处理;
同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,
其运算过程 是相同的,不需要额外的硬件电路。
int main()
{
//1+(-1)
//00000000 00000000 00000000 00000001 一的原码
//10000000 00000000 00000000 00000001 负一的原码
//原码相加为-2
//10000000 00000000 00000000 00000001负一的原码
//11111111 11111111 11111111 11111110负一的反码
//11111111 11111111 11111111 11111111负一的补码
//00000000 00000000 00000000 00000001 一的补码
//将两个补码相加,进位到第三十三个比特位上,所以输出结果为0,计算正确
return 0;
}
整数
1.有符号数
正数:原码,反码,补码相同
负数:原码,反码,补码不相同
2.无符号数
原码,反码,补码相同
int main()
{
int a=20;
//00000000 00000000 00000000 00010100
//0X 00 00 00 14
return 0;
}
这里设置的类型的用途在使用的时候定义该数据的类型,但具体怎么用,还要看是以什么样的形式打印出来。
unsigned int ch=-10;
%u打印的是无符号数,意思是你要我打印的一定是无符号数,不是无符号数,我也认为是无符号数。
%d打印的是有符号数,意思是你要我打印的一定是有符号数,不是有符号数,我也认为是有符号数。
什么大端小端:
大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;(倒着存)
小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地 址中。(正着存)
0X 11(高位) 22 33 44(低位) //左边是高位,右边是低位
编号小-低地址
编号大-高地址
大端字节序存储模式
小段字节序存储模式
为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元 都对应着一个字节,一个字节为8
bit。但是在C语言中除了8 bit的char之外,还有16 bit的short型,32 bit的long型(要看具体的编 译器),另外,对于位数大于8位
的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如 何将多个字节安排的问题。因此就
导致了大端存储模式和小端存储模式。
例如:一个 16bit 的 short 型 x ,在内存中的地址为 0x0010 , x 的值为 0x1122 ,那么 0x11 为
高字节, 0x22 为低字节。对于大端
模式,就将 0x11 放在低地址中,即 0x0010 中, 0x22 放在高地址中,即 0x0011 中。小端模式,
刚好相反。我们常用的 X86 结构是
小端模式,而 KEIL C51 则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以
由硬件来选择是大端模式还是小端
模式。
百度2015年系统工程师笔试题:
请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。(10分)
int main()
{
//把第一个字节的内容取出
int a=1;
char*p=(char*)&a;//强制转化类型
if(*p==1)
{
printf("小端存储");
}
else
{
printf("大端存储");
}
return 0;
}
封装成一个函数check_system
check_sys()
{
int a=1;
return *(char*)&a;
}
//指针类型的定义
//指针类型决定了指针进行解引用操作能访问几个字节,char*类型的指针只能访问一个字节,int*类型党的指针能够访问四个字节
//指针类型决定了指针+1,-1操作时,加的/减的是几个字节
int main()
{
//返回1,小端
//返回0,大端
int ret=check_sys;
if(ret==1)
{
printf("小端");
}
else
{
printf("大端");
}
check_sys();
return 0;
}
练习
1.
//输出什么?
#include
{
char a= -1;
//10000000 00000000 00000000 00000001原码
//11111111111111111111111111110反码
//11111111111111111111111111111补码
//11111111
signed char b=-1;
//11111111
unsigned char c=-1;
//11111111
printf("a=%d,b=%d,c=%d",a,b,c);
//发生整形提升,有符号数高位补位和符号位一致
//无符号数高位补0
return 0;
}
输出结果为-1,-1,255
2.
#include
int main()
{
char a = -128;
//10000000 00000000 00000000 10000000原码
//11111111 11111111 11111111 01111111反码
//11111111 11111111 11111111 10000000补码
//10000000
//11111111 11111111 11111111 10000000整形提升
printf("%u\n",a);//%u为无符号的十进制数,无符号数的补码和原码相同
return 0;
}
3.
#include
int main() {
char a = 128;
printf("%u\n",a);
return 0;
}
输出结果为4294967168
4.
int i= -20;
unsigned int j = 10;
printf("%d\n", i+j);
//按照补码的形式进行运算,最后格式化成为有符号整数
10000000 00000000 00000000 00010100//-20的原码
11111111 11111111 11111111 11101011//反码
11111111 11111111 11111111 11101100//补码
00000000 00000000 00000000 00001010//10的原码
11111111 11111111 11111111 11110110//10和20的补码相加结果为补码
11111111 11111111 11111111 11110101//反码
10000000 00000000 00000000 00001010//原码结果是-10
5.
#include
unsigned int i;
for(i = 9; i >= 0; i--)
{
printf("%u\n",i);
sleep(100);
}
因为i是一个无符号数,所以i永远也不可能变成负值,所以这个循环会变成死循环
char
signed char
unsigned char
1个字节
8个bit位
有符号char的范围-128-127
无符号char的范围0-255
6.
int main()
{
char a[1000];//数组下表0~999
int i;
for(i=0; i<1000; i++)
{
a[i] = -1-i;
}
printf("%d",strlen(a));
return 0;
}
数组中存储的数分别是-1,-2,-3,-4,-5,-6……
但一个char类型的变量只能够表示-128~127范围的数字
每一个数据被存储之后就会变成-128~127之间的数字
从右边的循环图可知道
从-1~-128之后变成127~1,1之后是0,遇到\0,strlen的读取就停止了
所以一共为255个数字
7.
#include
unsigned char i = 0;
int main()
{
for(i = 0;i<=255;i++)
{
printf("hello world\n");
}
return 0;
}
该代码为死循环
unsigned char的取值范围是0~255
255+1=0
所以这个循环条件会一直成立,从而陷入死循环。