如何通过不同类型重新解释数据? (type punning confusion) [英] How do I reinterpret data through a different type? (type punning confusion)

查看:171
本文介绍了如何通过不同类型重新解释数据? (type punning confusion)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  #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
保修;甚至不适用于适销性或特定用途的适用性。

我真的不明白什么时候和为什么我在某些地方遇到类型错误,



因此,严格别名


严格别名是一种假设,或C ++)编译器,
解除引用不同类型的对象的指针永远不会
引用相同的内存位置(即彼此之间的别名。)


第11行声明我打破严格别名。我没有看到一个情况,这可能会伤害任何东西 - 指针存在,立即取消引用,然后丢弃。在所有可能性,这将编译为零指令。这似乎绝对没有风险 - 我告诉编译器EXACTLY我想要的。



第15-16行继续不产生警告,即使指针相同的内存位置现在在这里留下来。这似乎是gcc中的错误。 / p>

第21行引出了警告,表明这不仅限于reinterpret_cast。



工会不会更好(强调我):



< blockquote>

...从
不是最近写入的联合成员读取的未定义的行为。 许多编译器以
非标准语言扩展实现了读取联盟的非活动成员
的能力。


此链接介绍使用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 -Wall
pun.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 $ ./pun
1065353216
1
1
1
me@Mint-VM ~/projects $ g++-5.3.0 --version
g++-5.3.0 (GCC) 5.3.0
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; 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:

Strict aliasing is an assumption, made by the C (or C++) compiler, that dereferencing pointers to objects of different types will never refer to the same memory location (i.e. alias each other.)

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):

...it's undefined behavior to read from the member of the union that wasn't most recently written. Many compilers implement, as a non-standard language extension, the ability to read inactive members of a union.

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)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆