/*1.10 "安静的改变"究竟有多少安静*/
/*目的是使C语言更加可靠*/
/*算术转换(K&R C)
*操作数 转换类型
*寻常算术转换(usual arithmetic conversion)
*操作数为char或short会转变成int
*操作数为float会转变成double
*首先,其中一个操作数为double,其他类型会转换成double,结果类型也为double(优先级较高)
*其次,其中一个操作数为long,其他类型会转换成long,结果类型也为long类型
*最后,其中一个操作数为unsigned,其他类型会转换成unsigned, 结果类型为unsigned类型
*其他情况,如果两个操作数的类型都为int,计算结果的类型也是int
*/
/*算术转换(ANSI C)
*字符和整型(整型升级)
*char、short int或者int型位段(bit-field),包括它们的有符号或无符号变体,以及枚举
*类型,可以使用在需要int或unsigned int的表达式中。如果int可以完整表示源类型的所有值
*那么该源类型的值就被转换为int,否则转换为unsigned int。这称为整型升级。
*寻常算术转换
*许多操作数类型为算术类型的双目会引发转换,并以类似的方式产生结果类型。
*它的目的是产生一个普通类型,同时也是结果的类型。这个模式称为“寻常算术转换”
*首先,一个操作数类型为long double,另一个操作数类型也被转换成long double
*其次,一个操作数类型为double, 另一个操作数类型也被转换成double
*最后,一个操作数类型为float, 另一个操作数类型也被转换成float
*否则,两个操作数进行整型升级,并执行下面的规则
*如果其中一个操作数的类型为unsigned long int, 那么另一个操作数也被转换成unsigned
*long int。其次,如果其中一个操作数的类型为long int, 而另一个操作数类型是unsigned int,
*如果long int能够完整表示unsigned int的所有值,那么unsigned int类型操作数被转换成long int;
*如果long int不能完整表示unsigned int的所有值,那么两个操作数都被转换成unsigned long int.
*再次,如果其中一个操作数的类型为long int, 那么另一个操作数被转换为long int。
*最后,如果其中一个操作数的类型是unsigned int, 那么另一个操作数也被转换成unsigned int.
*如果所有以上情况都不属于,那么两个操作数都为int。
*浮点操作数和浮点表达式的值可以用比类型本身所要求的更大的精度和更广的范围来表示,而它
*的类型并不因此改变。
*/
/*ANSI C标准所表示的意思大致如下:
*当执行算术运算时,操作数的类型如果不同,就会发生转换。数据类型一般朝着浮点精度更高,
*长度更长的方向转换。整型数如果转换为signed不会丢失信息,就转换为signed,否则转换为
*unsigned。
*/
/*K&R C采用无符号保留(unsigned preserving)原则,就是当一个无符号类型与int或者更小的整型混合使用时,结果类型为无符号类型。
*ANSI C标准采用值保留(value preserving)原则,就是当把几个整型操作数混合使用时(如下面的程序所示),结果类型既有可能是有符号数,也可能是无符号数,具体取决于操作数的类型的
相对大小。
*/
#include
int main( void ){
if( 1u - 2 >= 0 ){
printf( "the result of unsigned int number substract signed int number is larger than or equal to zero" );
} else{
printf( "the result of unsigned int number substract signed int number is smaller than zero" );
}
return 0;
}
/* 输出:
*/
#include
int main() {
if (-1 < (unsigned char) 1) { //equivalent to (int)-1 < (int)1
printf("-1 is less than (unsigned char)1: ANSI semantics");
} else { //equivalent to (unsigned int)(-1) < (unsigned int)1
printf("-1 NOT less than (unsigned char)1: K&R semantics");
}
return 0;
}
/* 输出:
*/
程序中的表达式在两种编译器下的编译器结果不同。-1的位模式是一样的,但一个编译器(ANSI C)将它解释为负数,另一个编译器(K&R C)却将它解释为无符号数,也就是变成了正数。
/*软件信条*/
#include
int array[] = {23, 34, 12, 17, 204, 99, 16};
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0])) //无符号整数(unsigned int)
int main() {
int d = -1, x;
// /*...*/
//error equivalent to (unsigned int)d <= (unsigned int)TOTAL_ELEMENTS - 2
if (d <= TOTAL_ELEMENTS - 2) {
x = array[d + 1];
}
// /*...*/
//correct //equivalent to (int)d <= (int)TOTAL_ELEMENTS - 2
if (d <= (int)TOTAL_ELEMENTS - 2) {
x = array[d + 1];
}
}
/*
*#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
*#define TOTAL_ELEMENTS (sizeof(array) / sizeof(int))
*因为前者可以在不修改#define语句的情况下改变数组的基本类型。
*/
/*无符号类型的建议*/
/*尽量不要在代码中使用无符号类型,以免增加不必要的复杂性。尤其是不要仅仅因为无符号
*不存在负值(如年龄、国债)就用它来表示数量
*尽管使用像int那样的有符号类型,这样在涉及升级混合类型的复杂细节时,不必担心边界
*情况(如-1被翻译为非常大的正数)。
*只有在使用位段和二进制掩码时,才可以使用无符号数。
*应该在表达式中使用强制类型转换,使操作数均为有符号数
*或者无符号数,这样不必由编译器来选择结果的类型
*/