a = f;
给定以下 C 代码,和有什么区别a = (int *) f;
?
float *f;
int *a;
...
a = f;
a = (int *) f;
float *f;
int *a;
a = f;
这个赋值是错误的(存在 C 约束冲突),指针类型之间没有隐式转换(with 除外void *
)。编译器可以拒绝编译带有这个赋值的程序。
鉴于:
float *f;
int *a;
这个:
a = f;
是违反约束的。它需要来自任何符合要求的编译器的诊断。在发出所需的诊断后,它可能会或可能不会拒绝该程序。(恕我直言,它应该这样做。)符合标准的编译器可能会选择仅通过警告(这符合诊断条件)来接受它,但是一旦这样做,程序的行为就未定义。执行此操作的编译器通常会生成从float*
to的隐式转换int*
,提供与强制转换(显式转换)相同的行为,但标准并不要求这样做。
不符合标准的编译器当然可以自由地做他们喜欢的任何事情。
结论:不要写那样的代码。即使您的编译器让您摆脱它,另一个编译器也可能不会。如果要从一种指针类型转换为另一种,请使用强制转换。除了有效性问题之外,演员阵容让读者更清楚地知道发生了一些有趣的事情。如果你的编译器给了你一个警告,请注意它。如果没有,请了解如何提高编译器的警告级别。
这个:
a = (int *) f;
获取f
( 类型float*
) 的值并将其显式转换为 type int*
,然后将该int*
值分配给a
. (我假设声明和赋值之间的某些内容已设置f
为某个有效值。)
如果f
是一个空指针,则转换定义良好,并产生一个类型为 的空指针int*
。将非空对象指针转换为另一种指针类型的规则是(引用N1570 6.3.2.3p7):
指向对象类型的指针可以转换为指向不同对象类型的指针。如果结果指针未正确对齐引用的类型,则行为未定义。否则,当再次转换回来时,结果将等于原始指针。
这种转换,假设int
和float
具有相同的大小并具有相似的对齐要求,可能旨在让您将float
对象视为int
对象。这称为“类型双关语”。如果大小不同int
,或者它们float
有不同的对齐要求,这很容易在您的脸上炸毁,使您的程序崩溃(如果您幸运的话)或给您垃圾结果(如果您不是)。(是的,使程序崩溃是一个好的结果;它让您知道存在问题。)
如果出于某种原因确实需要这样做,最好定义一个union
withint
和float
成员,或者用于将对象memcpy()
的内容复制float
到int
对象中。
但做这种事情很少有意义。如果要检查float
对象的表示,最好将其视为unsigned char
语言标准明确允许的数组。
左操作数具有原子、限定或非限定指针类型,并且(考虑到左操作数在左值转换后将具有的类型)两个操作数都是指向兼容类型的限定或非限定版本的指针,并且左侧指向的类型具有所有右边指向的类型的限定符。
因此,a = f
违反约束并调用未定义的行为。
在第二种情况下,您正在f
(通过强制转换)与'类型兼容。a
用 C 进行强制转换是合法的(不确定其他语言)。
但应该注意的是,在转换之后f
仍然是指针,float
并且每次将其分配给时都必须转换它a
。
您的代码将编译(至少在我的 linux 和 gcc 中)。但是你会得到一个警告。如果你在代码中的某个地方使用a = f;
然后使用a
,你会得到错误的数据,因为浮点数以不同的格式存储在内存中。即使您先进行转换,您也可能会得到错误的结果,但编译器会看到您的转换并假设您知道自己在做什么。
a = (int*) f;
明确表示您要将float*
指针强制转换为int*
指针。没有它,您将收到不兼容的指针类型错误。
a = f; //assignment
// is a constraint violation
a = (int *) f; //cast + assignment
将浮点指针显式转换为 int 指针。简单地隐藏编译器警告或错误。但是在运行时很可能会崩溃,因为取消引用指针时程序所期望的大小与现实不同。