[英]When is typecasting a pointer allowed?
我正在为考试而学习,下面给出的示例问题之一是:
“当分配给new_val时,以下哪个表达式(该表达式将替换HERE )将输出7 ? 选择所有适用项:
float m = 7.0
int *a = (int *) &m;
int new_val = HERE;
printf("%d\n", new_val);
(a)*(int *)&m
(b)* a
(c)(整数)米
(d)以上都不是。
答案仅是(c) 。
我已经在自己的机器上运行了该程序,发现符合答案。 但是,我想知道有人怎么能找到这个答案? 更一般而言,我在理解有关强制转换指针的规则时遇到了麻烦。 我已经阅读了StackOverflow上的其他几篇文章,对我来说并没有太大帮助。
我想知道是否有人可以帮助澄清我如何解决与此类似的问题。
但是使用
int new_val = (int)m;
使用int* a = ...
忽略在上一行中完成的所有操作
因此,您只是将原始浮点数m
投射回一个int。
编辑尝试以下操作:
#include "stdio.h"
int main(int argc, char** argv) {
float m = 7.1;
int new_val = (int)m;
printf("%d\n", new_val);
}
解决此问题的方法是查看每个选择答案,然后弄清该语句的含义。 考虑变量的类型。
但是,在这种情况下,将float *
强制转换为int *
只是意味着您要告诉编译器“您知道该存储有float
内存地址?像访问int
一样访问该内存”。 int
和float
不会以相同的方式存储在内存中,因此尝试以错误的格式访问它会产生无意义的结果。 强制转换指针不会转换指针指向的数据。
对于选项c,请注意,您没有强制转换指针,而是将float
转换为int
。 这是一个简单的转换。
这个问题是有缺陷的。 C标准允许(a),(b)和(c)中的每一个都打印“ 7”,并且还允许它们中的每一个都不打印“ 7”。
对于(a),我们有int new_val = * (int *) &m;
。 在这里, &m
类型为float *
,因此将float *
转换为int *
。 C 2018 6.3.2.3 7告诉我们我们可以进行这种转换:“指向对象类型的指针可能会转换为指向不同对象类型的指针。”但也“如果生成的指针未针对引用类型正确对齐,因此,在float
的对齐要求比int
严格的实现中,该行为不是由C标准定义的,因此,合格的C实现允许打印“ 7”,并且不允许打印“7”。 假设实现成功评估了转换而没有对齐问题,则应用*
。 下一节将对此进行介绍。
在(b)中,我们有int new_val = *a;
,其中a
已初始化为(int *) &m;
。 与(a)一样,此表达式将float *
转换为int *
,因此不符合上面的对齐问题。 但是,再次假设避免了对齐问题,它随后使用指针访问float
对象m
,就好像它是一个int
。 这违反了C 2018 6.5 7,其中声明“对象只能通过具有以下类型之一的左值表达式访问其存储的值:”然后继续列出各种选项,这些选项均不允许以以下方式访问float
:一个int
。 由于违反了此“应有”要求,C 2018 4 1告诉我们该行为未定义:“如果违反了在约束或运行时约束之外出现的“应有”或“不应”要求,则该行为未定义。 ”由于C标准未定义行为,因此允许的符合性实现允许打印“ 7”,而不允许打印“ 7”。
在(c)中,我们有int new_val = (int) m;
,其中m
是值为7的float
。这是定义明确的转换,结果为7,因此printf("%d\\n", new_val);
通常会打印“ 7”(带有换行符)。 但是,更早的问题仍然存在:即使使用new_val
正确定义,更早的声明int *a = (int *) &m;
执行可能导致未定义行为的转换。 在我们阅读new_val
的定义之前,这可能导致未定义的行为。 因此,与(a)和(b)一样,一致的实现方式允许打印“ 7”,而不允许打印“ 7”。
因为a = (int *)&m
,所以选项(a)和(b)相同。 在两种情况下,您都使用m
的地址,将其强制转换为int *
,然后取消引用。
(a)和(b)不起作用的原因是&m
是指向float
( float *
)的指针,而不是指向int
( int *
)的指针。
考虑两个指针,一个是指向Window
的指针,另一个是指向Joystick
的指针。 很明显,您不能将它们混在一起,对吗? 您不能将指向Window
的指针传递给需要指向Joystick
的指针的函数。 您可以投射指针,但这不会使Window
变成Joystick
。
因此,指向float
指针与指向int
指针是不兼容的,并且如果将指针转换为float
并指向int
的指针并尝试对其进行取消引用,则将得到垃圾。
但是(c)之所以有效,是因为这里要获取实际的float
值m
并要求编译器将该值转换为int
值。 编译器知道如何执行此操作并生成正确的代码。
您可能想知道,如果编译器知道如何将float
转换为int
,为什么不能将float
的指针转换为int
的指针呢? 实际上确实如此; 那是演员的目的。 但是它会转换指针,而不是指针指向的对象 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.