C++ 从const char*或LPCSTR生成std::字符串时数据丢失
我有一个返回LPSTR/const char*的函数,需要将其转换为std::string。我就是这样做的C++ 从const char*或LPCSTR生成std::字符串时数据丢失,c++,string,pointers,c++11,C++,String,Pointers,C++11,我有一个返回LPSTR/const char*的函数,需要将其转换为std::string。我就是这样做的 std::string szStr(foo(1)); 当foo返回一个32个字符长的字符串时,它在所有情况下都能正常工作,但失败了。通过这种方法,我得到了“。所以我认为它和长度有关。所以我改变了一点 std::string szStr(foo(1) , 32); 这给了我“0” 然后我尝试了另一种乏味的方法 const char * cstr_a = foo(1); const cha
std::string szStr(foo(1));
当foo返回一个32个字符长的字符串时,它在所有情况下都能正常工作,但失败了。通过这种方法,我得到了“
。所以我认为它和长度有关。所以我改变了一点
std::string szStr(foo(1) , 32);
这给了我“0”
然后我尝试了另一种乏味的方法
const char * cstr_a = foo(1);
const char * cstr_b = foo(2);
size_t ln_a = strlen(cstr_a);
size_t ln_b = strlen(cstr_b);
std::string szStr_a( cstr_a , ln_a );
std::string szStr_b( cstr_b , ln_b );
但奇怪的是,在这个方法中,两个指针都得到了相同的值,即foo(1)应该返回abc,foo(2)应该返回xyz。但这里cstr_a首先得到abc,但当cstr_b得到xyz时,cstr_a和cstr_b的值都变成xyz。我对此感到茫然和困惑
是的,我不能使用std::wstring
什么是foo?
foo基本上是从注册表读取一个值,并将其作为LPSTR返回。现在我需要读取的注册表中的一个值是MD5哈希字符串(32个字符),这就是它失败的地方
实际的Foo函数:
LPCSTR CRegistryOperation::GetRegValue(HKEY hHeadKey, LPCSTR szPath, LPCSTR szValue)
{
HKEY hKey;
CHAR szBuff[255] = ("");
DWORD dwBufSize = 255;
::RegOpenKeyEx(hHeadKey, (LPCSTR)szPath, 0, KEY_READ, &hKey);
::RegQueryValueEx(hKey, (LPCSTR)szValue, NULL, 0, (LPBYTE)szBuff, &dwBufSize);
::RegCloseKey(hKey);
LPCSTR cstr(szBuff);
return cstr;
}
StrResultMap RegValues;
std::string lid(CRegistryOperation::GetRegValue(HKEY_CURRENT_USER, REG_KEY_HKCU_PATH, "LicenseID"));
std::string mid(CRegistryOperation::GetRegValue(HKEY_CURRENT_USER, REG_KEY_HKCU_PATH, "MachineID"), 32);
std::string vtill(CRegistryOperation::GetRegValue(HKEY_CURRENT_USER, REG_KEY_HKCU_PATH, "ValidTill"));
std::string adate(CRegistryOperation::GetRegValue(HKEY_CURRENT_USER, REG_KEY_HKCU_PATH, "ActivateDT"));
std::string lupdate(CRegistryOperation::GetRegValue(HKEY_CURRENT_USER, REG_KEY_HKCU_PATH, "LastUpdate"));
RegValues["license_id"] = lid;
RegValues["machine_id"] = mid;
RegValues["valid_till"] = vtill;
RegValues["activation_date"] = adate;
RegValues["last_updated"] = lupdate;
原始演员代码:
LPCSTR CRegistryOperation::GetRegValue(HKEY hHeadKey, LPCSTR szPath, LPCSTR szValue)
{
HKEY hKey;
CHAR szBuff[255] = ("");
DWORD dwBufSize = 255;
::RegOpenKeyEx(hHeadKey, (LPCSTR)szPath, 0, KEY_READ, &hKey);
::RegQueryValueEx(hKey, (LPCSTR)szValue, NULL, 0, (LPBYTE)szBuff, &dwBufSize);
::RegCloseKey(hKey);
LPCSTR cstr(szBuff);
return cstr;
}
StrResultMap RegValues;
std::string lid(CRegistryOperation::GetRegValue(HKEY_CURRENT_USER, REG_KEY_HKCU_PATH, "LicenseID"));
std::string mid(CRegistryOperation::GetRegValue(HKEY_CURRENT_USER, REG_KEY_HKCU_PATH, "MachineID"), 32);
std::string vtill(CRegistryOperation::GetRegValue(HKEY_CURRENT_USER, REG_KEY_HKCU_PATH, "ValidTill"));
std::string adate(CRegistryOperation::GetRegValue(HKEY_CURRENT_USER, REG_KEY_HKCU_PATH, "ActivateDT"));
std::string lupdate(CRegistryOperation::GetRegValue(HKEY_CURRENT_USER, REG_KEY_HKCU_PATH, "LastUpdate"));
RegValues["license_id"] = lid;
RegValues["machine_id"] = mid;
RegValues["valid_till"] = vtill;
RegValues["activation_date"] = adate;
RegValues["last_updated"] = lupdate;
请帮我克服它。
谢谢。函数返回指向
GetRegValue
堆栈帧中缓冲区的指针。这不起作用:在GetRegValue
终止后,指针cstr
指向堆栈中某个未定义的值。尝试将szBuff
设置为静态,看看是否有帮助
LPCSTR CRegistryOperation::GetRegValue(HKEY hHeadKey, LPCSTR szPath, LPCSTR szValue)
{
HKEY hKey;
//Here:
static CHAR szBuff[255] = ("");
szBuff[0]=0;
DWORD dwBufSize = 255;
::RegOpenKeyEx(hHeadKey, (LPCSTR)szPath, 0, KEY_READ, &hKey);
::RegQueryValueEx(hKey, (LPCSTR)szValue, NULL, 0, (LPBYTE)szBuff, &dwBufSize);
::RegCloseKey(hKey);
LPCSTR cstr(szBuff);
return cstr;
}
更新:我没有强制要求返回std::string或传入缓冲区,因为那样会更改接口。将指针返回到静态缓冲区是一种常见的习惯用法,如果返回的指针值的生存期限制在几个范围内(如从缓冲区值构建std::string),则大多数情况下是没有问题的
多线程并不是真正的问题,因为几乎每个编译器现在都有某种形式的线程本地存储支持<代码>\uuu declspec(线程)静态字符szBuff[255]=(“”)例如,code>应该适用于Microsoft编译器,而gcc则适用于线程。C++11甚至为此提供了一个新的存储类说明符(thread\u local
)。不过,您不应该从信号处理程序调用GetRegValue,但这没关系——无论如何,您也不能在那里做太多的事情(例如,从堆中分配内存!)
更新:评论者认为,我不应该建议这样做,因为当再次调用GetRegValue时,指向静态缓冲区的指针将指向无效数据。虽然这显然是正确的,但我认为以此作为论据是错误的。为什么?看看这些例子:
- 从strdup()返回的指针在free()之前有效
- 指向使用new创建的内容的指针在删除之前是有效的李>
- 只要字符串没有修改,从string::c_str()返回的常量字符*就有效
- 如果删除了std::vector中的元素,则std::vector迭代器无效
- 如果删除了std::vector中的元素,则std::list迭代器仍然有效,除非它指向已删除的元素
- 从GetRegValue返回的指针在再次调用GetRegValue之前是有效的
- std::ifstream在以下情况下有效:…您知道,good()、fail()等等
说“看,如果你不够小心,事情就会变得无效”是没有意义的,因为编程不是粗心大意。我们正在处理对象,这些对象具有有效或无效的条件,如果对象具有定义良好的有效或无效条件,那么我们可以编写具有定义良好行为的程序。返回指向静态缓冲区(即线程本地)的指针具有定义良好的含义,开发人员可以使用它编写定义良好的程序。当然,除非说开发人员疏忽大意或懒得阅读例行程序的文档 > P>作为北欧主机的ANWSER的补充,从C或C++函数返回3种常用缓冲区的方法有:
- 使用静态缓冲区-简单而漂亮,直到出现重入问题(多线程或递归性)
- 将缓冲区作为输入参数传递,只需返回写入缓冲区的字符数-如果缓冲区的大小确实是常量,则返回ok
- malloc函数中的缓冲区(它在堆中而不在堆栈中),并以闪烁的红色记录调用者必须释放它
<>但是,当你把问题标记为C++时,你可以在函数中创建STD::string并返回它。C++函数允许返回STD::string,因为不同的操作符(复制构造函数、做作、……)自动地处理分配问题。 < P>可以避免返回一个已经超出范围的指针,返回一个<代码> STD::String 。
std::string CRegistryOperation::GetRegValue(HKEY hHeadKey, LPCSTR szPath, LPCSTR szValue)
{
HKEY hKey = 0;
CHAR szBuff[255] = { 0 };
DWORD dwBufSize = sizeof(szBuf);
if (::RegOpenKeyEx(hHeadKey, (LPCSTR)szPath, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
::RegQueryValueEx(hKey, (LPCSTR)szValue, NULL, 0, (LPBYTE)szBuff, &dwBufSize);
::RegCloseKey(hKey);
}
return std::string(szBuf);
}
那么
foo
到底在做什么?返回的c字符串是否以null结尾?行std::string szStr(foo(1))如果foo
返回以零结尾的字符序列,则code>是100%正确的。foo基本上是在读取
<代码>这就是它失败的地方。
如果这就是它失败的地方(很可能是),那么为什么这个代码不在问题中呢?LPCSTR
是指针,是吗?它指向一个本地数组,并在函数结束时销毁该数组时悬空。取消引用返回的指针(这是字符串的构造函数所做的)具有未定义的行为。@当您将数组强制转换为指针时,数组参数首先衰减为指向第一个值的指针。因此,您返回的是一个指向szBuff
的第一个元素的指针,该元素是一个本地数组。使szBuf
静态的问题是,如果函数被多次调用,并且调用方保留返回的poi