如何在不丢失编译器内部数据的情况下进行类型转换?
例如:
int i = 10; UINT k = (UINT) k; float fl = 10.123; UINT ufl = (UINT) fl; // data loss here? char *p = "Stackoverflow Rocks"; unsigned char *up = (unsigned char *) p;
编译器如何处理这种类型转换?显示位的低级示例将受到高度赞赏.
好吧,首先请注意,强制转换是将一种类型的值转换为另一种类型的值的显式请求.强制转换也总是会产生一个新对象,这是一个由强制转换操作符返回的临时对象.但是,转换为引用类型不会创建新对象.该值引用的对象将重新解释为不同类型的引用.
现在回答你的问题.请注意,转换有两种主要类型:
促销:这种类型可以被认为是从可能更窄的类型转换为更宽的类型.从char到int,short到int,float to double都是促销.
转换:这些允许从long 转换为int,int转换为unsigned int等等.它们原则上可能导致信息丢失.-1
例如,如果为无符号类型对象分配a,会有规则.在某些情况下,错误的转换可能会导致未定义的行为.如果指定的double大于浮点数可以存储到float的值,则不会定义行为.
让我们来看看你的演员阵容:
int i = 10; unsigned int k = (unsigned int) i; // :1 float fl = 10.123; unsigned int ufl = (unsigned int) fl; // :2 char *p = "Stackoverflow Rocks"; unsigned char *up = (unsigned char *) p; // :3
此演员表会导致转换.不会丢失数据,因为10保证由a存储unsigned int
.如果整数是负数,则该值基本上会包围unsigned int的最大值(参见4.7/2).
该值10.123
被截断为10.这里,不造成丢失的信息,很明显.当10适合unsigned int时,定义了行为.
这实际上需要更多关注.首先,从字符串文字转换为不推荐的转换char*
.但是我们在这里忽略它.(见这里).更重要的是,如果你转换为无符号类型会发生什么?实际上,每个5.2.10/7都没有指定结果(注意该转换的语义与在这种情况下使用reinterpret_cast相同,因为这是唯一能够做到这一点的C++转换):
指向对象的指针可以显式转换为指向不同类型对象的指针.除了将"指向T1的指针"的rvalue转换为"指向T2的指针"类型(其中T1和T2是对象类型,T2的对齐要求不比T1更严格)并返回其原始类型时原始指针值,这种指针转换的结果是未指定的.
因此,char *
再次强制转换后,只能安全地使用指针.
在您的示例中,两个C风格的演员阵容是不同类型的演员.在C++中,您通常会编写它们
unsigned int uf1 = static_cast(fl);
和
unsigned char* up = reinterpret_cast(p);
第一个执行算术转换,它会截断浮点数,因此会丢失数据.
第二个不对数据进行任何更改 - 它只是指示编译器将指针视为不同的类型.这种演员需要注意:它可能非常危险.
C和C++中的"Type"是在编译器中处理变量时赋给变量的属性.除了C++中的虚函数/ RTTI之外,该属性在运行时不再存在.
编译器使用变量类型来确定很多东西.例如,在将float赋值给int时,它将知道它需要转换.两种类型都可能是32位,但具有不同的含义.CPU可能有一条指令,但编译器会知道调用转换函数.即
& __stack[4] = float_to_int_bits(& __stack[0])
从char*到unsigned char*的转换甚至更简单.这只是一个不同的标签.在位级,p和up是相同的.编译器只需要记住*p需要符号扩展而*up不需要.