来源:www.cncfan.com | 2006-4-28 | (有5484人读过)
ANSI C中的整型升级
char,short int或者int型位段(bit-field),包括它们的有符号或无符号变型, 以及枚举类型,可以使用在需要int或unsigned int的表达式中, 如果int可以完整地表示源类型的所有值,那么该类型的值就转换为int,否则转换为unsigned int。
ANSI C中的寻常算术转换
当执行算术运算时,操作数的类型如果不同,就会发生转换。 数据类型一般朝着浮点精度更高、长度更长的方向转换, 整型数如果转换为signed不会丢失信息,就转换为signed,否则就转换为unsigned。 这个称为值保留(value preserving)原则,与K&R C所采用的无符号保留(unsigned preserving)原则不同。
int d = -1; if (d <= sizeof(arr)/sizeof(arr[0])) ... 这样的比较语句有问题,sizeof运算符返回无符号数。 if语句在signed int和unsigned int之间测试相等性, 按照上面的说法,可以这样解释: 首先,signed int和unsigned int长度相同,不会向更长的方向转换。 其次,signed int不能完整地表示unsigned int的所有值。 因此,signed int d被转换为unsigned int类型。 这样,-1就变成一个非常巨大的正整数,导致比较结果与预期的不符。
解决的方法是使用强制转换,(int)(sizeof(arr)/sizeof(arr[0]))。 我在VC++ 6.0和DEV-C++ 4.9.9.0中尝试了上面那段代码,的确如此。
不要因为无符号数不存在负值而用它表示数量(如年龄、国债等), 尽量使用int之类的有符号数,这样在混合运算中, 这样就不必担心边界情况(如-1被翻译为非常大的正数)。
只有在使用位段和二进制掩码时,才使用无符号数。 应该在表达式中使用强制类型转换,使所有的操作数均为有符号数或无符号数, 这样就不必由编译器来选择结果的类型。 C语言中的类型转换比一般人想象中的要广泛得多。 在涉及类型小于int或double的表达式中,都有可能出现类型转换。
printf(" %d ", sizeof 'A'); 的结果是4, 是int的长度。
整型提升就是char、short int和位段类型(无论signed或unsigned)以及枚举类型将被提升为int, 前提是int 能够完整地容纳原先的数据,否则将被转换为unsigned int。
ANSI C表示,如果编译器能够保证运算结果一致, 也可以省略类型提升——这通常出现在表达式中存在常量操作数的时候。
另一个会发生隐式类型转换的地方就是参数传递。 在K&R C中,由于函数的参数也是表达式,所以也会发生类型提升。 在ANSI C中,如果使用了适当的函数原型,类型提升便不会发生,否则也会发生。 在被调用函数的内部,提升后的参数被裁减为原先声明的大小。
这就是为什么单个的printf()格式字符串%d能适用于几个不同类型, short、char或int,而不论实际传递的是上述类型的哪一个。 函数从堆栈中(或寄存器中)取出的参数总是int类,并在printf或其他被调用函数里按统一的格式处理。 printf是一个可变参数函数,此时一般的参数提升始终会发生。 原型之痛
ANSI C函数原型的目的是使C语言成为一种更加可靠的语言。 建立原型就是为了消除形参和实参之间的类型不匹配。
如果使用了函数原型,缺省参数提升就不会发生。 如果参数声明为char,则实际传递的也是char。 如何进行强制类型转换,为何要进行类型强制转换
“强制类型转换(cast)”这个术语从C语言一诞生就开始使用, 既用于“类型转换”,也用于“消除类型歧义”。
(float)3 是一个类型转换,而且数据的实际二进制位发生了改变, (float)3.0 用于消除类型歧义,这样编译器可以从一开始就选择正确的位模式。
有些人认为它之所以命名为强制类型转换是因为它们可以把有些东西变得不完整。 source: 《Expert C Programming》
|