C / C ++编译器如何处理具有不同值范围的类型之间的类型转换?

如何在不丢失编译器内部数据的情况下进行类型转换?

例如:

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 ,则会有规则。 在某些情况下,错误的转换可能导致未定义的行为。 如果指定的double大于float可以存储到float的double,则不会定义行为。

让我们来看看你的演员阵容:

 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 
  1. 此演员表会导致转换。 不会丢失数据,因为10保证由unsigned int存储。 如果整数是负数,则该值基本上会包围unsigned int的最大值(参见4.7 / 2 )。
  2. 10.123被截断为10.这里显然会导致信息丢失。 当10适合unsigned int时,定义了行为。
  3. 这实际上需要更多关注。 首先,有一个从字符串文字到char*的弃用转换。 但是我们在这里忽略它。 (见这里 )。 更重要的是,如果你转换为无符号类型会发生什么? 实际上,每个5.2.10 / 7都没有指定结果(注意该转换的语义与在这种情况下使用reinterpret_cast相同,因为这是唯一能够做到这一点的C ++转换):

指向对象的指针可以显式转换为指向不同类型对象的指针。 除了将“指向T1的指针”的rvalue转换为“指向T2的指针”类型(其中T1和T2是对象类型,并且T2的对齐要求不比T1更严格)并返回其原始类型时原始指针值,这种指针转换的结果是未指定的。

因此,再次char *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不需要符号扩展。

演员表示不同的东西,取决于他们是什么。 它们只能是数据类型的重命名,所表示的位没有变化(整数类型和指针之间的大多数转换都是这样的),或者甚至不保留长度的转换(例如在大多数编译器中的double和int之间) 。 在许多情况下,转换的含义根本没有指定,这意味着编译器必须做一些合理的事情,但不必准确记录什么。

演员表甚至不需要产生可用的价值。 像char * cp; float * fp; cp = malloc(100); fp = (float *)(cp + 1); char * cp; float * fp; cp = malloc(100); fp = (float *)(cp + 1); 几乎肯定会导致指向float的指针错位,如果程序试图使用它,会导致某些系统上的程序崩溃。