用typedef和#define定义类型
常用typedef声明新的类型名来替代已有的类型名,这主要是便于移植。例如,在程序中我们经常会看到:
typedef unsigned int u32
.............
u32 var=3;
第1行用typedef声明了一个类型u32来替代unsigned int,这样比较方便,从u32可以看出来这是一个unsigned型数据(前面的u就是这个意思),后面的32表示的是一个32位的数据。
第3行用刚才的u32定义了一个变量var。
#define u32 unsigned int
...............
u32 var=3;
在这段程序中可以看到用#define来定义新的数据类型。
第1行用#define定义了一个u32来代替unsigned int。
第3行用刚才声明的新类型u32定义了一个变量var。
以上两种类型的定义方法的不同之处在于typedef是在编译阶段处理的,而#define是在预处理阶段处理的。
用signed和unsigned修饰数据类型
关键词signed和unsigned常作为数据类型修饰符加在数据类型的前面,如unsigned int。signed称为有符号型,unsigned称为无符号型。
例如: signed int 和 unsigned int.
其中,signed int 表示有符号整型,一个 int 型数据类型是32位,前面加 signed 修饰符后,最高位用作符号位(0表示正数,1表示负数),剩下的31位才是数据的有效位,因此 signed int 能表示的数据范围是从-2^31 到2^31-1.而unsigned int 表示无符号整型,32位有效数据位,因此一个unsigned int表示数据范围:0~2^32-1.
volattile和强制类型转换
C语言共有32个关键字,而volattile就是其中一个。
我们为什么要在这里用到这个关键字?因为volattile用来修饰变量时表示该变量的值可能会被硬件改变。因此每次读取这个变量值时都需要我们重新从内存中读取这个变量的值,而不是保存在寄存器中的备份。这里说的不是很好,还是可以去百度上自己对此做深刻的了解。
上篇文章中的关于数据类型和“模子”的讨论中可以看到,不同的数据类型的长度也是不一样的,
因此当操作数的数据类型不一样时需要用到的类型转换(C语言内部有自己的转换规则)将其称为强制类型转换。
例如:
#define rBWSCON
(*(volatile unsigned*)0x48000000)
为了方便理解,可以暂时把 volattile 去掉,所以重要的是理解((volatile unsigned)0x48000000),0x48000000仅仅是一个十六进制的数而已,但是前面的用(unsigned*)修饰的话则表示将这个数据强制转化为一个地址指针,即(unsigned*)48000000指向内存地址中0x48000000处,准确的说是指向内存中从这个数据开始连续4个字节内存片中(0x48000000~0x48000003),因此(unsigned*)48000000其实就是(unsigned int*)48000000的缩写。如图。
然后在(unsigned*)48000000前面加一个*,这里的 是指指针运算符(也叫“间接访问”运算符),表示取该内存单元中的数据。
最后再看
#define rBWSCON
(( unsigned*)0x48000000)
表示用#define定义了一个新的类型 rBWSCON,rBWSCON的含义和((unsigned)0x48000000)完全相同。都表示内存单元0x48000000中的数据。因此在程序中如果看到 rBWSCON=0x00000003,就相当于
(( unsigned)0x48000000)=0x00000003,其实就是想内存单元48000000中写入了相对应的数据,如图。
所以上文中的volattile表示每次读取这个变量值时都需要我们重新从内存中读取这个变量的值,而不是保存在寄存器中的备份。