我想以便携方式(C99)将一种类型的数据重新解释为另一种类型。 我不谈论投射,我想要一些给定数据的重新解释。 此外,通过 portable 我的意思是它不会破坏C99规则 - 我不意味着重新解释的值在所有系统上都是相同的。
我知道3种不同的重新解释数据的方法,但其中只有两种是可移植的:
这不是便携式的 - 它打破了严格的别名规则。
/* #1 Type Punning */
float float_value = 3.14;
int *int_pointer = (int *)&float_value;
int int_value = *int_pointer;
这是依赖于平台的,因为它在写入int
后会从联合中读取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));
我的问题:
答案 0 :(得分:18)
解决方案2 便携式 - 通过工会的类型惩罚在C99中一直是合法的,并且它在TC3中明确说明,它在6.5.2.3节中添加了以下脚注:
如果用于访问union对象内容的成员不是 与上次用于在对象中存储值的成员相同, 值的对象表示的适当部分是 如上所述,重新解释为新类型中的对象表示 在6.2.6(一个过程有时被称为"类型双关语")。这可能是一个 陷阱表示。
附件J仍然将其列为未指明的行为,这是一个已知的缺陷,并已通过C11更正,但已更改
存储在[中的最后一个工会成员以外的工会成员的值未指定]
到
与最后存储的成员之外的union成员对应的字节值 进入[未指定]
这并不是什么大不了的事,因为附件只是提供信息,而不是规范性的。
请记住,您仍然可能会遇到未定义的行为,例如
答案 1 :(得分:2)
联合解决方案定义为C中的memcpy(AFAIK,C ++中的UB),请参阅DR283
可以将指针强制转换为指向(signed / unsigned /)char的指针,所以
unsigned char *ptr = (unsigned char*)&floatVar;
然后访问ptr [0]到ptr [sizeof(floatVar)-1]是合法的。
答案 2 :(得分:0)
为了安全起见,我会使用字节数组(unsigned char)而不是'int'来保存值。
答案 3 :(得分:0)
数据类型int
是非可移植类型的示例,因为字节顺序可以更改平台之间的字节顺序。
如果您想要可移植,则需要定义自己的类型,然后在要移植到的每个平台上实现它们。然后为您的数据类型定义转换方法。据我所知,这是完全控制字节顺序等的唯一方法。
答案 4 :(得分:0)
如果要避免严格别名规则,则需要先转换为char指针:
float float_value = 3.14;
int *int_pointer = (int *)(char *)&float_value;
int int_value = *int_pointer;
但请注意,您可能拥有sizeof(int) > sizeof(float)
,在这种情况下,您仍会获得未定义的行为