简体   繁体   English

从LPVOID检索字符串

[英]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. 可以说我有这样的功能,其中lpData持有一个指向我想要的数据的指针。

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? lpData拥有一个指针吗? (But my function is lpData not *lpData) so it isn't working? (但是我的功能是lpData而不是* lpData),所以它不起作用? 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. 这意味着您的字符串不是以Null结尾的,也就是说,它没有NUL字节( 0 )来标记字符串的结尾。

C strings have to be null-terminated .* When you log a C string ( char * ), it keeps logging characters until it finds a NUL . C字符串必须以空值结尾 。*当您记录C字符串( char * )时,它将一直记录字符,直到找到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). 许多函数可以将char *旁边的长度作为附加参数(例如, string构造函数)或其他形式(例如, printf格式字符串中的宽度说明符)。

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!). 同时,从LPVOID (aka void * ,又称指针指向任何东西)转换为LPVOID * (aka void ** ,又称指针指向任何东西的指针)然后再转换为char * (指针到字符)是错误的(并且应该在第二次转换中向您发出编译器警告;如果您收到警告而忽略了它们,请不要这样做!)。 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; 而且,通常最好使用现代强制转换而不是C样式强制转换,并且在没有缺点的情况下最好使用const正确; 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. 几乎可以肯定这是错误的。** LPVOID只是指向一堆字符。 You're saying you want to interpret those characters as if they were a string object. 您说的是要将这些字符解释为好像是string对象。 But a string object is some header information (maybe a length and capacity, etc.) plus a pointer to a bunch of characters. 但是string对象是一些标头信息(可能是长度和容量等)以及指向一串字符的指针。 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". *是的,您使用的是C ++,而不是C,但是char *是“ C字符串”。

** 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. **如果实际上有一个string对象,并且该string对象一直存在于某个地方,并且将指向该对象的指针保存在LPVOID ,并且现在已经对其进行了检索(例如,使用SetWindowLongPtr / GetWindowLongPtr ),则将其从LPVOIDstring *会很有意义。 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 .) (如果是,则不需要reinterpret_cast void *的全部要点是它没有被解释,因此没有什么可以从其重新解释的。只需使用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. 一些标准的C ++库使用特殊的分配器将标头放在字符之前,并返回指向第一个字符的指针,以便可以在char *可以使用的任何地方使用string Inside the string class, every method has to fudge the this pointer backward; string类内部,每个方法都必须使this指针向后移动。 for example, instead of just saying m_length it has to do something like static_cast<_string_header *>(this)[-1]->m_length . 例如, m_lengthstatic_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. 但是另一种方法不起作用-如果您只有一堆字符,而不是string对象,该软糖将读取恰好在字符之前分配的所有字节,然后尝试将它们解释为整数,因此您可能最终以为您的字符串长度为0或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....
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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