本文介绍了如何通过不同类型重新解释数据? (type punning confusion)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! #include< iostream> int main(int argc,char * argv []) { int a = 0x3f800000; std :: cout<< a<< std :: endl; static_assert(sizeof(float)== sizeof(int),Oops); float f2 = * reinterpret_cast< float *>(& a); std :: cout<< f2<< std :: endl; void * p =& a; float * pf = static_cast< float *>(p); float f3 = * pf; std :: cout<< f3<< std :: endl; float f4 = * static_cast< float *>(static_cast< void *>(& a)); std :: cout<< f4<< std :: endl; } 我从我的可信赖的编译器得到以下信息: me @ Mint-VM〜/ projects $ g ++ - 5.3.0 -std = c ++ 11 -o pun pun.cpp -fstrict-aliasing -Wall pun.cpp:在函数'int main(int,char **)': pun.cpp:11:45:warning:dereferencing类型冲突的指针将会破坏严格别名规则[ -Wstrict-aliasing] float f2 = * reinterpret_cast< float *>(& a); ^ pun.cpp:21:61:warning:dereferencing类型冲突的指针将会破坏严格别名规则[-Wstrict-aliasing] float f4 = * static_cast< float *> (static_cast< void *>(& a)); ^ me @ Mint-VM〜/ projects $ ./pun 1065353216 1 1 1 me @ Mint-VM 〜/ projects $ g ++ - 5.3.0 --version g ++ - 5.3.0(GCC)5.3.0 版权所有(C)2015 Free Software Foundation,Inc. 这是自由软件;请参阅复制条件的来源。有NO 保修;甚至不适用于适销性或特定用途的适用性。 我真的不明白什么时候和为什么我在某些地方遇到类型错误, 因此,严格别名:第11行声明我打破严格别名。我没有看到一个情况,这可能会伤害任何东西 - 指针存在,立即取消引用,然后丢弃。在所有可能性,这将编译为零指令。这似乎绝对没有风险 - 我告诉编译器EXACTLY我想要的。 第15-16行继续不产生警告,即使指针相同的内存位置现在在这里留下来。这似乎是gcc中的错误。 / p> 第21行引出了警告,表明这不仅限于reinterpret_cast。 工会不会更好(强调我): ...从不是最近写入的联合成员读取的未定义的行为。 许多编译器以非标准语言扩展实现了读取联盟的非活动成员的能力。 此链接介绍使用memcpy,但是似乎只是隐藏了你真正想要完成的工作。 对于某些系统,它是一个必要的操作,将指针写入int寄存器,字节流,并将这些字节组装成一个浮点数或其他非整数类型。 这是正确的,符合标准的方式是什么?解决方案使用 memcpy : memcpy(& f2,& a,sizeof(float)); 如果你担心类型安全和语义,你可以轻松地写一个包装: void convert(float& x,int a){ memcpy(& x,& a,sizeof(float)) ; } 如果需要,您可以使此包装模板满足您的需求。 #include <iostream>int main(int argc, char * argv[]){ int a = 0x3f800000; std::cout << a << std::endl; static_assert(sizeof(float) == sizeof(int), "Oops"); float f2 = *reinterpret_cast<float *>(&a); std::cout << f2 << std::endl; void * p = &a; float * pf = static_cast<float *>(p); float f3 = *pf; std::cout << f3 << std::endl; float f4 = *static_cast<float *>(static_cast<void *>(&a)); std::cout << f4 << std::endl;}I get the following info out of my trusty compiler:me@Mint-VM ~/projects $ g++-5.3.0 -std=c++11 -o pun pun.cpp -fstrict-aliasing -Wallpun.cpp: In function ‘int main(int, char**)’:pun.cpp:11:45: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] float f2 = *reinterpret_cast<float *>(&a); ^pun.cpp:21:61: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] float f4 = *static_cast<float *>(static_cast<void *>(&a)); ^me@Mint-VM ~/projects $ ./pun1065353216111me@Mint-VM ~/projects $ g++-5.3.0 --versiong++-5.3.0 (GCC) 5.3.0Copyright (C) 2015 Free Software Foundation, Inc.This is free software; see the source for copying conditions. There is NOwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.I don't really understand when and why I get type-punned errors in some places and not in others.So, strict aliasing:Line 11 claims I'm breaking strict-aliasing. I don't see a case where this can possibly hurt anything - the pointer "comes into existence", is immediately dereferenced, then thrown away. In all likelyhood, this will compile down to zero instructions. This seems like absolutely no risk - I'm telling the compiler EXACTLY what I want.Lines 15-16 proceed to NOT elicit a warning, even though the pointers to the same memory location are now here to stay. This appears to be a bug in gcc.Line 21 elicits the warning, showing that this is NOT limited to just reinterpret_cast.Unions are no better (emphasis mine):This link talks about using memcpy, but that seems to just hide what you're really trying to accomplish.For some systems, it is a required operation to write a pointer to an int register, or receive an incoming byte stream and assemble those bytes into a float, or other non-integral type.What is the correct, standards-conforming way of doing this? 解决方案 Use memcpy:memcpy(&f2, &a, sizeof(float));If you are worried about type safety and semantics, you can easily write a wrapper:void convert(float& x, int a) { memcpy(&x, &a, sizeof(float));}And if you want, you can make this wrapper template to satisfy your needs. 这篇关于如何通过不同类型重新解释数据? (type punning confusion)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
08-20 08:53
查看更多