下面一个小程序,演示了c语言中类型提升带来的一个小问题。
//test.c
#include <stdio.h>
int array[]={23,34,45,56,67,78};
#define TOTAL_ELEMENTS (sizeof(array)/sizeof(array[0]))
int main()
{
int d=-1,
x=3;
if(d<=TOTAL_ELEMENTS-2)
x=array[d+1];
printf("the value of x is %d/n",x);
return 0;
}
编译运行,结果如下:
alei@alei-desktop:~$ gcc test.c -o test
alei@alei-desktop:~$ ./test
the value of x is 3
为什么结果是3而不是23呢?
先看ANSI C手册中的关于寻常算术转换的规定。
首先,如果一个操作书的类型是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。
简言之,当进行算术运算时,操作数的类型如果不同,就会发生转换。数据类型一般朝着浮点精度更高,长度更长的防线转换,整型数如果转换为signed 不会丢失信息,就转换为signed,否则转换为unsigned。
再看上面的程序。
TOTAL_ELEMENTS是unsigned int类型的(因为sizeof()的返回类型是无符号整数)。if在signed int和unsigned int之间测试相等性,所以d被提升为unsigned int 类型的。只是表达式的值为假。要修正这个问题,可以进行强制类型转换:
if(d<=(int)TOTAL_ELEMENTS-2)