这工作,但我在最后得到怪异字符
这意味着,您的字符串ISN 'null null-terminated - 也就是说,它没有NUL
字节(0
)标记字符串的结尾。 *当您记录一个C字符串(char *
)时,它会一直记录字符,直到找到一个NUL
。如果字符串末尾没有一个字符串,它将继续通过随机内存直到找到一个(或者直到您遇到页面错误并崩溃)。这不好。而且没有办法解决它;一旦你失去了长度,就没有办法让它恢复原状。
但是,未终止的字符串及其长度可能会有用。许多函数的长度可以与char *
一样,作为额外的参数(例如,string
构造函数)或其他方式(例如printf
格式字符串中的宽度说明符)。所以,如果你取长度,并且只调用也占用长度的函数 - 或者只是创建一个以null结尾的副本并使用它,那么你很好。所以:
void foo(LPVOID lpData, int cchData) {
string sData(static_cast<const char *>(lpData), cchData);
// now do stuff with sData
}
同时,从LPVOID
铸造(又名void *
,又名指针到任何东西),以LPVOID *
(又名void **
,又名指针,指针到任何东西),以便然后转换为char *
(指针TO-字符)是错误的(并且应该在第二次播放时给你一个编译器警告;如果你得到警告并忽略它们,不要这样做!)。此外,使用现代演员而不是C型演员阵容通常会更好,并且在没有缺陷的情况下最好保持正确的阵容;它只是让读者更加明确,面对未来的维护更安全。
最后:
string *datastring = reinterpret_cast<std::string *>(lpData);
这几乎肯定是错的**的LPVOID
只是在一串字符的指点。你说你想要将这些角色解释为它们是一个string
对象。但是一个string
对象是一些标题信息(可能是长度和容量等)以及指向一堆字符的指针。治疗一个与其他会导致垃圾或崩溃。***
*是的,你正在使用C++,不C,但char *
是一个“C字符串”。
**如果你确实有,你已经更让某处string
对象,你在LPVOID
藏一个指向对象,现在已经取回它(例如,用SetWindowLongPtr
/GetWindowLongPtr
),然后从铸LPVOID
到string *
会有意义。但我怀疑你在做什么。 (如果你是,那么你不需要reinterpret_cast
。的void *
整个的一点是,它没有解释,所以没有什么距离。只需使用static_cast
重新解释。)
***或者说,最糟糕的是,它似乎可以工作,但随后会导致难以遵循的崩溃或腐败。某些标准的C++库使用特殊的分配器将标题放在字符之前,并返回指向第一个字符的指针,以便可以在char *
可以使用的任何位置使用string
。在string
类中,每种方法都必须将指针向后隐藏起来;例如,而不是仅仅说m_length
它必须做类似static_cast<_string_header *>(this)[-1]->m_length
。但反过来也行不通 - 如果你只有一堆字符,而不是一个对象,那么这个软件将读取在字符之前分配的任何字节,并尝试将它们解释为一个整数,所以你可能会认为你有一个长度为0的字符串,或者182423742341241243.
'LPVOID'已经是'void *'了。如果你传递一个指向'std :: string'的指针,只需使用'static_cast'。 –
chris
为什么从'LPVOID'('void *',任何指针)转换为'LPVOID *'('void **',指向任何指针的指针)? – abarnert