2

I just discovered reinterpret_cast in C++ and I am trying to learn more about it. I wrote this code:

struct Human{
    string name;
    char gender;
    int age;
    Human(string n, char g, int a) : name(n), gender(g), age(a) {}
};

int main()
{
    Human h("John", 'M', 26);
    char* s = reinterpret_cast<char*>(&h);
    Human *hh = reinterpret_cast<Human*>(s);
    cout << hh->name << " " << hh->gender << " " << hh->age << endl;
}

It works pretty well, exactly as expected. Now I want convert the char * to an std::string and then from this string get back the Human object:

int main()
{
    Human h("John", 'M', 26);
    char* s = reinterpret_cast<char*>(&h);

    string str = s;
    Human *hh = reinterpret_cast<Human*>(&str);

    cout << hh->name << " " << hh->gender << " " << hh->age << endl; // prints wrong values
}

Does anyone have an idea to overcome this ?

Thank you.

Omar Aflak
  • 2,918
  • 21
  • 39
  • 2
    Although there are ways to make this work, this smells funny. In fact, this smells like an http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem . So, what is the _real_ problem you think you need to solve using this approach? – Sam Varshavchik Feb 27 '16 at 16:24
  • That first example is a gross violation of [the strict aliasing rule](http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule). – Some programmer dude Feb 27 '16 at 16:24
  • 1
    Well, as it's explained in the linked article, a "char *" is exempt from aliasing. Even if this is actually OK, it's still not recommended, though. – Sam Varshavchik Feb 27 '16 at 16:28
  • Thank you for responding. I am actually trying to send objects through sockets in native C++ (I mean without using any external library). I saw this [https://gist.github.com/codemonkey85/5860625](https://gist.github.com/codemonkey85/5860625) and I thought it may work for sockets...? – Omar Aflak Feb 27 '16 at 16:37
  • 1
    @A.Omar Ah, then yes you can convert a pointer to an object to another pointer. But, and this is important, trying to send anything complex over a socket will in almost all cases not work as expected. Take the normal `std::string` for example. A `std::string` object doesn't actually contain an actual string, it contains a *pointer* to a string, and sending a `std::string` object will send the pointer and not the data (string) it points to. In the other process, that pointer you receive is not going to point to the same thing (if at any valid memory at all). – Some programmer dude Feb 27 '16 at 16:40
  • 1
    @A.Omar: While this can theoretically work sometimes it's not a good idea. Firstly your structs cannot contain a single pointer (or a pointer in an object) because it makes no sense. Additionally numerous things such as bitness, type size, packing, compiler, compiler version and endianness differences can change the way a struct is laid out in memory across platforms. If you need to serialize an object - just write it byte by byte in a known format. – Matti Virkkunen Feb 27 '16 at 16:43

1 Answers1

1

In your second program when you do

string str = s;

you create a completely new object that is totally unrelated to the pointer s. Getting the address from str will give you a pointer to str, and not the "string" it contains.

Also, using reinterpret_cast is a way to tell the compiler "I know what I am doing", and if you don't actually know what's happening then you will undoubtedly march into the territory of undefined behavior which is what will happen when you try to initialize str with the "string" pointed to by s, since it's not really a string.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Not to mention that since `s` isn't even a pointer to a proper C string, at best you will get something meaningless in the `std::string`, and in the worst case your program will crash when it tries to read from unallocated memory. – Matti Virkkunen Feb 27 '16 at 16:28
  • How does `string str = s`; possibly create an object unrelated to pointer `s`, when `s` was essential to its construction? Do you mean unrelated to it's address? – GManNickG Feb 27 '16 at 16:31
  • @GManNickG I didn't say a new pointer, said a new *object*, and attempting to get the address of the new object will result in a pointer to that new object and that is not related to `s` in any way. – Some programmer dude Feb 27 '16 at 16:36
  • I understand your sentence, I'm saying "you create a completely new object that is totally unrelated to the pointer s" is misleading and adds confusion to your answer. `str` is very related to the pointer `s`, it's entire (attempt) at initialization is via the pointer `s`. – GManNickG Feb 27 '16 at 16:38
  • 1
    @GManNickG: Even though the constructor takes in `s` it does not store the actual value of `s` in any way within the object. All it does is copy the (nonsensical) data pointed to it into the `std::string`. Therefore I don't think the resulting `std::string` has a lasting relationship to `s`. – Matti Virkkunen Feb 27 '16 at 16:39
  • @MattiVirkkunen: .......I know how `std::string` works. Now you're moving the goalpost from "has a relationship to `s`" to "has a lasting relationship to `s`." – GManNickG Feb 27 '16 at 16:41
  • @GManNickG: And I think you're just pointlessly arguing semantics now. – Matti Virkkunen Feb 27 '16 at 16:44
  • @MattiVirkkunen: I've been consistent since the first comment. The answer loses clarity, especially for a beginner, because of its attempt to completely remove any relationship between `str` and `s`, instead of explain it. – GManNickG Feb 27 '16 at 16:48
  • 1
    @GManNickG But the pointer `s` is only passed as an argument to the constructor (in this case), that's the closest relationship the string object `str` and the pointer `s` have. Once the constructor returns how is `str` and `s` related in any way? They aren't. The string object `str` has its own pointer, that is pointing to some completely other memory than `s`. – Some programmer dude Feb 27 '16 at 16:51
  • @GManNickG Lets say that `s` is actually pointing to a valid string, and you do `std::string str = s`, would you expect `str[0] = 'F'` change the string pointed to by `s`? Or doing `s[0] = 'B'`, would that change `str[0]`? No it doesn't, they are simply not related in any way. – Some programmer dude Feb 27 '16 at 16:52
  • @JoachimPileborg: Like I said, I know how `std::string` works. Beginners don't. Telling them that `s` has nothing to do with `str` isn't useful. Explaining that it's used to tell `str` what initial contents to have is. No, of course I don't expect `str` to be related to `s` after construction, that's not the same as "a completely new object that is totally unrelated to the pointer s". – GManNickG Feb 27 '16 at 16:54
  • @A.Omar It just happens that the first member of `h` is a `std::string` object, and most likely the first member of that `std::string` is a pointer to the actual string. This is, however, really crossing the line into *undefined behavior*. While `s` might be a pointer to `char` (and as such act like a C-style string) it's not actually a real string. This is the danger of using `reinterpret_cast` (as well as C-style casting). – Some programmer dude Feb 27 '16 at 16:54
  • This entire comment thread would be most confusing for a beginner at all, though, so I'm just going to delete it later. – GManNickG Feb 27 '16 at 16:54
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/104734/discussion-between-gmannickg-and-joachim-pileborg). – GManNickG Feb 27 '16 at 17:06