表达式(十)
五、强制类型转换运算符
强制类型转换运算符(cast operator)执行显式地类型转换,其语法格式如下所示:
(type-name) cast-expression
其中type-name是类型名,cast-expression是被强制类型转换的表达式;如果type-name是void类型,cast-expression类型可以是任意类型;如果type-name不是void类型,cast-expression类型可以是原子的、限定的或者非限定的标量类型(scalar type)。
int i = 5; double d = (double)i;
类型名中的大小表达式(size expressions)和typeof运算符在每次对强制类型转换表达式评估时会被评估。强制类型转换运算符的操作数会被评估,其值会转换成( )内类型名指定的类型。如果( )内类型名是void,则因为操作数的副作用对操作数进行评估,并丢弃其值,这与操作数作为表达式语句单独使用时的情况相同;如果( )内类型名与操作数的类型相同,则不会对操作数的值和类型有影响。无论哪种情况,强制类型转换不会生成左值。
int i = 5; int j = 6; double d = 3.14; (void) ++i; //(void) ++i表达式类型是void类型,i值为6。 (int) ++j; //(int) ++j表达式类型是int类型,值为7,j值为7。 (int) d; //(int) d表达式类型是int类型,值为3,d值为3.14。
如果表达式的范围和精度大于( )内类型名指定类型的范围和精度,即使表达式的类型与( )内类型名指定类型相同,强制类型转换也会进行转换,并删除额外的范围和精度。以float类型为例,当宏FLT_EVAL_METHOD值为1或者2时,实现会根据double类型或者long double类型的范围和精度评估所有float类型的操作和常量。强制类型转换删除额外的范围和精度,是将扩展精度的值存储到标准大小内存位置。
除以下情况外,涉及指针的转换都应使用强制类型转换来实现:
-- 简单赋值运算中,左操作数具有原子的、限定的或者非限定的指针类型,左操作数和右操作数都是指向兼容类型的限定或者非限定版本的指针,并且左操作数指向类型具有右操作数指向类型的所有类型限定符。
int i = 3; const int *ptr = &i;
-- 简单赋值运算中,左操作数具有原子的、限定的或者非限定的指针类型,两个操作数中一个操作数是指向对象类型的指针,另一个操作数是指向void类型的限定或者非限定版本的指针,并且左操作数指向类型具有右操作数指向类型的所有类型限定符。
int *ptr = malloc(5*sizeof(int));
-- 简单赋值运算中,左操作数具有原子的、限定的或者非限定的nullptr_t类型,右操作数是空指针常量或者具有nullptr_t类型。
(注:nullptr_t类型是预定义常量nullptr的类型。该类型使用非常有限,只有在需要将nullptr与其它表达式类型区分的情况下使用。该类型只有一个值nullptr。该类型对象的默认初始化或者空初始化等同于使用nullptr初始化。)
-- 简单赋值运算中,左操作数具有原子的、限定的或者非限定的指针类型,右操作数是空指针常量或者具有nullptr_t类型。
int *ptr = nullptr;
-- 简单赋值运算中,左操作数具有原子的、限定的或者非限定的bool类型,右操作数是指针或者具有nullptr_t类型。
bool b;
b = &b;
指针类型不能转换成浮点类型;浮点类型也不能转换成指针类型。
double d = 1.0; double *ptr = NULL; (double *) d; //非法。 (double) ptr; //非法。
nullptr_t类型不得转换为void、bool或者指针类型外的任何其它类型。如果目标类型是nullptr_t类型,转换表达式应为空指针常量或者nullptr_t类型。
(注:转换为void *类型的、值为0的整数常量表达式或者预定义常量nullptr称为空指针常量(null pointer constant)。<stddef.h>头文件中的宏NULL也被定义为空指针常量。)
int i; int *ptr = &i; (nullptr_t)NULL; //合法。 (nullptr_t)ptr; //非法。