简体   繁体   中英

C++: odd behavior with reinterpret_cast

I have the following snippet

#include <iostream>

using namespace std;

class foobar
{
    public:
    unsigned int a = 97;
    unsigned int b = 98;
    unsigned int c = 99;
};


class barfoo
{
    public:
    char a:32,b:32,c;

};


int main(){
    foobar * f = new foobar();
    barfoo * b = (reinterpret_cast<barfoo *>(f));
    cout << b->a << "-" << b->b << "-" << b->c;

}

Output:

a-b-c

However, if I specify the width of c in barfoo, it doesn't work (all the values are 0). Observe

#include <iostream>

using namespace std;

class foobar
{
    public:
    unsigned int a = 97;
    unsigned int b = 98;
    unsigned int c = 99;
};


class barfoo
{
    public:
    char a:32,b:32,c:32;

};


int main(){
    foobar * f = new foobar();
    barfoo * b = (reinterpret_cast<barfoo *>(f));
    cout << b->a << "-" << b->b << "-" << b->c;

}

Output:

--

The chars are all 0

Any idea why this is happening?

Link to ideone first snippet -- working

Linke to ideone second snippet -- not working

Compiler is gcc-5.1 Thanks!!

This reinterpret_cast does not meet the requirements for defined behavior, so while the assignment of it's result is acceptable any subsequent access of b is undefined behavior:

barfoo * b = (reinterpret_cast<barfoo *>(f));

A reinterpret_cast must meet one of these conditions, where the foobar is the DynamicType and barfoo is the AliasedType:

  • AliasedType is (possibly cv-qualified) DynamicType
  • AliasedType and DynamicType are both (possibly multi-level, possibly cv-qualified at each level) pointers to the same type T
  • AliasedType is the (possibly cv-qualified) signed or unsigned variant of DynamicType
  • AliasedType is an aggregate type or a union type which holds one of the aforementioned types as an element or non-static member (including, recursively, elements of subaggregates and non-static data members of the contained unions): this makes it safe to obtain a usable pointer to a struct or union given a pointer to its non-static member or element.
  • AliasedType is a (possibly cv-qualified) base class of DynamicType
  • AliasedType is char or unsigned char : this permits examination of the object representation of any object as an array of unsigned char.

Since the AliasedType does not fall into any of these conditions the accessing of the reinterpret_cast 's result is undefined behavior.

First, check if the 2 classes are even same size. Conceivably, padding and alignment may make the positions of bitfields a, b, and c different from positions of normal members a, b and c etc. Why are you using char for 32-bit bitfields? My compiler warns about bitfield exceeding size of type.

Otherwise (if you change char to unsigned int for barfoo class), regardless of any standardese-UB thrown at you, the reinterpret_cast and access has good chance of working. Maybe even more so if you use the well-supported and well-established idiom of type-punning through a union.

Type-punning through a union is a way of telling your compiler 'these 2 pointers of different types may alias, do not make radical optimizations assuming that they may not alias'.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM