C语言中的数据类型及其转换详解
1. C语言中的数据类型
C语言中的类型按其组成可以分为简单类型和构造类型,按是否预定义了类型名字和值集可以分为基本类型和非基本类型,按是否加了类型限定符可以分为限定类型和非限定类型。
ANSI C99标准中类型定义的BNF语法如下图。
![](https://pic002.cnblogs.com/images/2012/364723/2012021520503478.jpg)
说明:
- typedef可以定义新数据类型,如typedef long int FOUR_BYTE_INT,即定义了和long int一样的数据类型FOUR_BYTE_INT。
- 如果typedef时加入了类型限定符或存储区分符,比如typedef volatile char KEYBOARD,则KEYBOARD k等价于volatile char。
- 按照一般规范,新定义的数据类型同义名需要全部大写,以免与变量名混淆。
- 利用类型定义typedef,可以为所要表示对象指定比原数据类型更合适的名字,如typedef float SPEED。
- 利用类型定义typedef,可以提高的程序的在不同编译器上升级的可维护性,比如有些类型在某些编译器下没有,只需要改变类型定义即可轻松维护。
- 类型定义typedef一般用于定义比较长或复杂的名字,如struct类型,即便于书写,又提高了程序的可读性。
- 类型定义typedef与预处理指令#define的区别:
- 处理时间不同:前者是编译过程中,后者是编译过程前;
- 处理方法不同:前者是类型替换,而后者是简单的字符串替换,在某些情况下不适合,比如定义多个变量的地方:
1 #define POINTER int *;
2 POINTER a,b;
-
-
- 如果是想定义两个指针类型a,b,预处理后是int * a,b。只有a是int *,是错误的。
-
ANSI C99标准中规定的数据类型如下图所示。
![](https://pic002.cnblogs.com/images/2012/364723/2012021520081634.jpg)
说明:
- 同一行类型的语义相同,即可以相互替代。
- long float类型与double相同,故在C99标准中没有此类型。
- 部分编译器也提供了unsigned float和unsigned double,最好不要使用,以免影响程序的可移植性。
- int默认是signed,所以int, signed, signed int三者等价。其它unsigned的情况类似。char默认情况不确定。
2. C语言中数据类型的长度
ANSI C99标准中定义了两类(四个)类型修饰符:long/short和unsigned/signed。
C99标准规定,long类型不能比变通类型短,short类型不能比普通类型长。而unsigned与signed的区别在实现上是有无符号的区别,而是使用上是取值范围的区别,两者表示范围相同,但前者全是正数,后者关于0对称。
说明:
- long/short可以修饰int,long还可以修饰double。
- unsigned/signed可以修饰int, char,不可以修饰浮点型。
- int长度是机器的字长,short int是半个字长,long int是一个或两个字长。
- unsigned/signed长度与普通类型一样,只是表示区间不同。
3. C语言中数据类型的转换
类型转换分为显示和隐式两种,前者比较简单,这里只讲后者。下面是C99标准中给出的各种类型对象的基本转换规则:
- 枚举常量:转换成int,如超出int范围,则转成long int等
- 浮点类型:
- 如果转成整类型,只保留整数部分,如果超出整类型表示范围,则转换错误;
- 如果向上转成double/long double,值不变;
- 如果向下转成float/double等,如果能用float/double表示,则正常,如果超出表示范围,则转换错误,而如果在表示范围内,但精度降低,则要依赖于编译器的处理了;
- 整类型:short int/char/枚举类型/位域类型都可转换成int,如果超出int表示范围,则提升到unsigned int。
- 对于二元运算符中的普通算术运算转换,C99标准给出了如下图所示的转换规则:
![](https://pic002.cnblogs.com/images/2012/364723/2012021523285241.jpg)
说明:
- 对于unsigned char和unsigned short int的整型提升问题,C99标准给出“保值”的转换方法:方法是将unsigned char和unsigned short int转换成int,如果超出表示范围,则转成unsigned int。
- 对于表格中第五行,long int与unsigned int的情况,在vc6.0没有这样实现,是直接转成unsigned int。
4. 测试练习
1 char a = 0xb6;
2 short b = 0xb600;
3 int c = 0xb6000000;
4
5 if ( a == 0xb6) puts("a");
6 if ( b == 0xb600) puts("b");
7 if ( c == 0xb6000000) puts("c");
答案:
在VC或x86的gcc下,只会打印出 c ,而linux的gcc则会打印出a和c。
解释:
char在前两者默认是signed char,而后者默认是unsigned char。因此当整型提升时,在前两者的编译器下,三条语句分别变成如下情况:
1 if ( 0xffffffb6 == 0x000000b6) puts("a");
2 if ( 0xffffb600 == 0x0000b600) puts("b");
3 if ( 0xb6000000 == 0xb6000000) puts("c");
而在linux的gcc编译下,则是下面的情况:
1 if ( 0x000000b6 == 0x000000b6) puts("a");
2 if ( 0xffffb600 == 0x0000b600) puts("b");
3 if ( 0xb6000000 == 0xb6000000) puts("c");