简体   繁体   中英

retrieving string from LPVOID

Can someone explain and help me out here please. Lets say i have function like this where lpData holds a pointer to the data i want.

void foo(LPVOID lpData) {

}

What is the proper way to retreive this. This works but i get weird characters at the end

void foo(LPVOID lpData) {
    LPVOID *lpDataP = (LPVOID *)lpData;
char *charData = (char*)lpDataP;
    //i log charData....
}

I would prefer to use strings but I don't understand how to retrieve the data, i just get null pointer error when i try to use string. lpData holds a pointer right? (But my function is lpData not *lpData) so it isn't working? Am i doing this all wrong?

string *datastring = reinterpret_cast<std::string *>(lpData);

is what im trying.

This works but i get weird characters at the end

That means that your string isn't null-terminated—that is, it doesn't have a NUL byte ( 0 ) marking the end of the string.

C strings have to be null-terminated .* When you log a C string ( char * ), it keeps logging characters until it finds a NUL . If there wasn't one on the end of the string, it'll keep going through random memory until it finds one (or until you hit a page fault and crash). This is bad. And there's no way to fix it; once you lose the length, there's no way to get it back.

However, an unterminated string along with its length can be useful. Many functions can take the length alongside the char * , as an extra argument (eg, the string constructor) or otherwise (eg, width specifiers in printf format strings).

So, if you take the length, and only call functions that also take the length—or just make a null-terminated copy and use that—you're fine. So:

void foo(LPVOID lpData, int cchData) {
    string sData(static_cast<const char *>(lpData), cchData);
    // now do stuff with sData
}

Meanwhile, casting from LPVOID (aka void * , aka pointer-to-anything) to LPVOID * (aka void ** , aka pointer to pointer-to-anything) to then cast to char * (pointer-to-characters) is wrong (and should be giving you a compiler warning in the second cast; if you're getting warnings and ignoring them, don't do that!). Also, it's generally better to use modern casts instead of C-style casts, and it's always better to be const-correct when there's no down side; it just makes things more explicit to the reader and safer in the face of future maintenance.

Finally:

string *datastring = reinterpret_cast<std::string *>(lpData);

This is almost certainly wrong.** The LPVOID is just pointing at a bunch of characters. You're saying you want to interpret those characters as if they were a string object. But a string object is some header information (maybe a length and capacity, etc.) plus a pointer to a bunch of characters. Treating one as the other is going to lead to garbage or crashes.***


* Yes, you're using C++, not C, but a char * is a "C string".

** If you actually have a string object that you've kept alive somewhere, and you stashed a pointer to that object in an LPVOID and have now retrieved it (eg, with SetWindowLongPtr / GetWindowLongPtr ), then a cast from LPVOID to string * would make sense. But I doubt that's what you're doing. (If you are, then you don't need the reinterpret_cast . The whole point of void * is that it's not interpreted, so there's nothing to reinterpret from. Just use static_cast .)

*** Or, worst of all, it may appear to work, but then lead to hard-to-follow crashes or corruption. Some standard C++ libraries use a special allocator to put the header right before the characters and return a pointer to the first character, so that a string can be used anywhere a char * can. Inside the string class, every method has to fudge the this pointer backward; for example, instead of just saying m_length it has to do something like static_cast<_string_header *>(this)[-1]->m_length . But the other way around doesn't work—if you just have a bunch of characters, not a string object, that fudge is going to read whatever bytes happened to be allocated right before the characters and try to interpret them as an integer, so you may end up thinking you have a string of length 0, or 182423742341241243.

There are at least two ways:

void foo(LPVOID lpData)
{
    char *charData = (char*)lpData;
    //i log charData....
}

or

void foo(LPVOID lpData)
{
    char *charData = static_cast<char*>lpData;
    //i log charData....
}

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