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