我想以可移植的方式将一种类型的数据重新解释为另一种类型(c99)。
我不是在说选角,我想重新解释一些给定的数据。
此外,我所说的可移植性并不意味着它违反了C99规则——我并不是说所有系统上重新解释的值都是相等的。
我知道三种不同的方法来重新解释数据,但其中只有两种是可移植的:
这是不可移植的-它打破了严格的别名规则。
/* #1 Type Punning */
float float_value = 3.14;
int *int_pointer = (int *)&float_value;
int int_value = *int_pointer;
这依赖于平台,因为它在将
int
写入union后从union读取float
值。但它没有违反任何c99规则,因此应该可以工作(如果sizeof(int) == sizeof(float)
)。/* #2 Union Punning */
union data {
float float_value;
int int_value;
};
union data data_value;
data_value.float_value = 3.14;
int int_value = data_value.int_value;
应该没问题,只要
sizeof(int) == sizeof(float)
/* #3 Copying */
float float_value = 3.14;
int int_value = 0;
memcpy(&int_value, &float_value, sizeof(int_value));
我的问题:
这是对的吗?
你知道用其他的方法以可移植的方式重新解释数据吗?
最佳答案
解决方案2是通过联合使用的可移植式双关语,在C99中一直是合法的,TC3对此进行了明确说明,TC3在第6.5.2.3节中添加了以下脚注:
如果用于访问联合对象内容的成员不是
与上次用于在对象中存储值的成员相同,
值的对象表示的适当部分是
重新解释为新类型中的对象表示,如所述
在6.2.6中(有时称为“类型双关语”的过程)。这可能是
陷阱表示。
附件J仍然将其列为未经规范的行为,这是一个已知的缺陷,并已用C11进行了纠正,C11已更改
联合成员的值,而不是存储到[中的最后一个成员的值未指定]
到
对应于联合成员而不是最后存储的成员的字节值
进入[未指明]
这没什么大不了的,因为附件只是信息性的,而不是规范性的。
记住,你最终还是会有不明确的行为(如
通过创建陷阱表示
如果成员具有指针类型,则会违反别名规则(由于不需要统一的指针表示,因此无论如何不应通过类型punning进行转换)
如果联合成员的大小不同-只有上次在存储中使用的成员的字节具有指定的值;特别是,将值存储在较小的成员中也会使较大成员的尾部字节无效
如果成员包含填充字节,而这些字节总是采用未指定的值