我知道,我已经看到了,但我找不到任何好的解释为什么这个未定义的行为:
#include <stdio.h>
#include <stdint.h>
//Common union for both types
union float_int {
float f;
uint32_t i;
};
int main(void) {
union float_int fi;
//This should be problematic
uint32_t* i_ptr = (uint32_t *)&fi.f;
fi.f = 10.0f;
printf("%f : %u\r\n", fi.f, fi.i); //Prints: 10.000000 : 1092616192 which is OK
printf("%u\r\n", *i_ptr); //Prints: 1092616192 which is also OK
return 0;
}
如果我们检查内存表示,两者都是4-bytes
长,所以在指向或类似的情况下没有内存溢出。
这种未定义的行为如何?
int main() {
union float_int fi;
void* v_ptr = &fi.f;
uint32_t* i_ptr = (uint32_t *)v_ptr;
}
此代码仍然是未定义的行为吗?我想将float
号码视为unsigned integer 32-bits
。
为什么使用memcpy
是唯一可行的方式?
答案 0 :(得分:1)
这不是严格的别名,而是严格别名的违规。
首先,你正在做
uint32_t* i_ptr = (uint32_t *)&fi.f; //converting to a non-character type pointer
然后,您尝试通过
访问它 printf("%u\r\n", *i_ptr); //access value via incompatible lvalue expr.
导致问题。 float
和uint32_t
不是兼容类型。
引用C11
,章节§6.5/ P7
对象的存储值只能由具有其中一个的左值表达式访问 以下类型: 88)
- 与对象的有效类型兼容的类型,
- 与对象的有效类型兼容的类型的限定版本
- 对应于有效类型的有符号或无符号类型 对象,
- 对应于合格版本的有符号或无符号类型的类型 有效的对象类型,
- 包含其中一种上述类型的聚合或联合类型 成员(包括,递归地,子集合或包含的联合的成员),或
- 字符类型。
在回复评论时,让我们看看C11
,章节§6.2.6.1
存储在任何其他对象类型的非位字段对象中的值由
n × CHAR_BIT
组成 bits,其中n
是该类型对象的大小,以字节为单位。该值可以复制到 类型unsigned char [n]
的对象(例如,memcpy
);得到的字节集是 称为值的对象表示。
和
某些对象表示不需要表示对象类型的值。如果存储 对象的值具有这样的表示,并由左值表达式读取 没有字符类型,行为是未定义的。 [...]这种表述被称为 陷阱表示。
答案 1 :(得分:0)
浮点数和整数表示形式彼此不同。 这就是为什么通过定义这样一个联合,不是一个好的用例。
在您的示例中,执行从void *到uint32_t *的转换。 转换是在指针级别完成的。 这意味着i_ptr指向内存中的一个位置,被视为一个整数,而不是自己更改位。
总而言之,如果您希望此转换工作,您需要修改变量的内部表示。例如:
UIImage