Converting std::string to LPCSTR [duplicate] - c++

As I clould not pass LPCSTR from one function to another (Data get changed) I tried passing it as a string.
But later I need to again convert it back to LPSTR. While trying the conversion I am getting the above error:
cannot convert from 'std::string' to 'LPSTR'
How can I resolve this?

That's just because you should use std::string::c_str() method.
But this involves const_cast in given case because const char * returned by c_str() can not be assigned to a non-constant LPSTR.
std::string str = "something";
LPSTR s = const_cast<char *>(str.c_str());
But you must be sure that lifetime of str will be longer that that of LPTSTR variable.
Another mention, if code compiles as Unicode-conformant, then types LPTSTR and std::string are incompatible. You should use std::wstring instead.
Important note: If you pass the resulting pointer s from above to a function which tries to modify the data it is pointing to this will result in undefined behaviour. The only way to properly deal with it is to duplicate the string into a non-const buffer (e.g. via strdup)

If you need an LPSTR, that means the string will/may be modified. std::string::c_str() returns a const pointer, and you can't just const_cast it away and hope all is good in the world, because it isn't. The string may be changed in all sorts of nasty ways, and your original std::string will be oblivious to all of them.
Try this instead:
// myFunction takes an LPSTR
std::string cppString = "something";
LPSTR cString = strdup( cppString.c_str() );
try {
myFunction( cString );
cppString = cString;
} catch(...) {
free( cString );
}
Wrap the string in a smart pointer and get rid of the try...catch for bonus points (don't forget the custom deleter).

There is a function on std::string c_str() . However I doubt that you could not use a std::string in your case.

Are you running somestringvariablename.c_str()?
That should work.

An LPSTR can be substituted with by using a TCHAR (i.e. found in tchar.h). So if you have a std::string, you can use the method std::string::c_str().

If the function, you are calling does not write to string, but only reads it, then you can simply use string::c_str method. If it is going to write something, then you probably should ensure that your string has enough space by calling string::reserve().

Related

Loss of data while building a std::string from const char * or LPCSTR

I have a Function which returns a LPSTR/const char * and I need to convert it to a std::string. This is how I am doing it.
std::string szStr(foo(1));
It works just fine in all the cases just when foo returns a 32 characters long string it fails. With this approach I get "". So I thought it had to do something with the length. So I changed it a bit.
std::string szStr(foo(1) , 32);
This gives me "0"
Then I tried another tedious method
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 );
But strangely enough in this method both the pointers are getting the same value, viz foo(1) should return abc and foo(2) should return xyz. But here cstr_a is first getting abc but the moment cstr_b gets xyz, the value of both cstr_a and cstr_b becomes xyz. I am dazed and confused with this.
And yes, I cannot use std::wstring.
What is foo?
foo is basically reading a value from the registry and returning it as a LPSTR. Now one the value in the registry which I need to read is a MD5 hashed string (32 charecters) That's where it fails.
The Actual Foo function:
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;
}
The Original cast code:
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;
Kindly help me get over it.
Thanks.
As a complement to Nordic Mainframe's anwser, there are 3 common ways to return a buffer from a C or C++ function :
use a static buffer - simple and nice until you have re-entrancy problems (multiple threads or recursivity)
pass the buffer as an input parameter, and simply return the number of characters written to it - ok if the size of buffer is really a constant
malloc the buffer in the function (it is in the heap and not in the stack) and document in flashing red that it must be freed by caller
But as you tagged your question as C++, you could create the std::string in the function and return it. C++ functions are allowed to return std::string because the different operators (copy constructor, affectation, ...) take care automatically of the allocation problem.
You can avoid returning a pointer to a buffer which has gone out of scope by returning a std::string directly.
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);
}
The GetRegValue function returns a pointer to a buffer in GetRegValue's stack frame. This does not work: after GetRegValue terminates the pointer cstr points to undefined values somewhere in the Stack. Try to make szBuff static and see if that helps.
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;
}
UPDATE: I did not mandate to return std::string, or pass a buffer in, because that would change the interface. Returning a pointer to a static buffer is a common idiom and mostly unproblematic if the lifetime of the returned pointer value is limited to a few scopes (Like for building a std::string from the buffer value).
Multithreading isn't really an issue aynmore, because almost every compiler now has some form of thread local storage support right in the language. __declspec(thread) static CHAR szBuff[255] = (""); for example, should work for Microsoft compilers, __thread for gcc. C++11 even has a new storage class specifier for this (thread_local). You shouldn't call GetRegValue from a signal handler though, but that's OK - you can't do too much there anyway (for example allocate memory from the heap!).
UPDATE: Commenters argue, that I should not suggest this, because the pointer to the static buffer will point to invalid data when GetRegValue is called again. While this is obviously true, I think it is wrong to make an argument from that. Why? Look at these examples:
A pointer returned from strdup() is valid until free()
A pointer to something created with new is valid until deleted.
A const char * returned from string::c_str() is valid as long as the string is not modified.
A std::vector iterator is invalid, if an element from the std::vector is erased.
A std::list iterator is still valid, if an element from the std::vector is erased, unless it points to the erased element.
A pointer returned from GetRegValue is valid until GetRegValue is called again.
a std::ifstream is valid when,..you know, good(), fail() and so on.
There is no point in saying, "look, the thing gets invalid when you are not careful enought", because programming is not about being careless. We are handling objects, which have conditions under which they are valid or not and if an object has well defined conditions under which it is valid or not, then we can write programs with well defined behaviour. Returning a pointer to a static buffer (that is thread-local) has a well defined meaning and a developer can use this to write a well defined program. Unless said developer is negligent or too lazy to read the documentation of the routine of course.

Convert std::string to char * alternative

I have done a search in google and been told this is impossible as I can only get a static char * from a string, so I am looking for an alternative.
Here is the situation:
I have a .txt file that contains a list of other .txt files and some numbers, this is done so the program can be added to without recompilation. I use an ifstream to read the filenames into a string.
The function that they are required for is expecting a char * not a string and apparently this conversion is impossible.
I have access to this function but it calls another function with the char * so I think im stuck using a char *.
Does anyone know of a work around or another way of doing this?
In C++, I’d always do the following if a non-const char* is needed:
std::vector<char> buffer(str.length() + 1, '\0');
std::copy(str.begin(), str.end(), buffer.begin());
char* cstr = &buffer[0];
The first line creates a modifiable copy of our string that is guaranteed to reside in a contiguous memory block. The second line gets a pointer to the beginning of this buffer. Notice that the vector is one element bigger than the string to accomodate a null termination.
You can get a const char* to the string using c_str:
std::string str = "foo bar" ;
const char *ptr = str.c_str() ;
If you need just a char* you have to make a copy, e.g. doing:
char *cpy = new char[str.size()+1] ;
strcpy(cpy, str.c_str());
As previous posters have mentioned if the called function does in fact modify the string then you will need to copy it. However for future reference if you are simply dealing with an old c-style function that takes a char* but doesn't actually modfiy the argument, you can const-cast the result of the c_str() call.
void oldFn(char *c) { // doesn't modify c }
std::string tStr("asdf");
oldFn(const_cast< char* >(tStr.c_str());
There is c_str(); if you need a C compatible version of a std::string. See http://www.cppreference.com/wiki/string/basic_string/c_str
It's not static though but const. If your other function requires char* (without const) you can either cast away the constness (WARNING! Make sure the function doesn't modify the string) or create a local copy as codebolt suggested. Don't forget to delete the copy afterwards!
Can't you just pass the string as such to your function that takes a char*:
func(&string[0]);

cannot convert from 'std::string' to 'LPSTR'

As I clould not pass LPCSTR from one function to another (Data get changed) I tried passing it as a string.
But later I need to again convert it back to LPSTR. While trying the conversion I am getting the above error:
cannot convert from 'std::string' to 'LPSTR'
How can I resolve this?
That's just because you should use std::string::c_str() method.
But this involves const_cast in given case because const char * returned by c_str() can not be assigned to a non-constant LPSTR.
std::string str = "something";
LPSTR s = const_cast<char *>(str.c_str());
But you must be sure that lifetime of str will be longer that that of LPTSTR variable.
Another mention, if code compiles as Unicode-conformant, then types LPTSTR and std::string are incompatible. You should use std::wstring instead.
Important note: If you pass the resulting pointer s from above to a function which tries to modify the data it is pointing to this will result in undefined behaviour. The only way to properly deal with it is to duplicate the string into a non-const buffer (e.g. via strdup)
If you need an LPSTR, that means the string will/may be modified. std::string::c_str() returns a const pointer, and you can't just const_cast it away and hope all is good in the world, because it isn't. The string may be changed in all sorts of nasty ways, and your original std::string will be oblivious to all of them.
Try this instead:
// myFunction takes an LPSTR
std::string cppString = "something";
LPSTR cString = strdup( cppString.c_str() );
try {
myFunction( cString );
cppString = cString;
} catch(...) {
free( cString );
}
Wrap the string in a smart pointer and get rid of the try...catch for bonus points (don't forget the custom deleter).
There is a function on std::string c_str() . However I doubt that you could not use a std::string in your case.
Are you running somestringvariablename.c_str()?
That should work.
An LPSTR can be substituted with by using a TCHAR (i.e. found in tchar.h). So if you have a std::string, you can use the method std::string::c_str().
If the function, you are calling does not write to string, but only reads it, then you can simply use string::c_str method. If it is going to write something, then you probably should ensure that your string has enough space by calling string::reserve().

How to create a CString from an array of chars?

Need to log the content of buf using the LogMethod() below the problem is that
LogMethos only accepts a "Const CString&"
char buf[1024];
strcpy(buf, cErrorMsg);
// need to pass to LogMethod "buf" how do i do that?
log.LogMethod(const CString &);
Thans
Rev
Reversed
If you're talking about MFC CString, as far as I can tell, it should have a non-explicit constructor taking TCHAR const *. In other words, the following should work.
log.LogMethod(buf);
If it doesn't, please post the error message.
log.LogMethod(CString(buf));
This will avoid the problem where the compiler won't automatically create the CString object using the appropriate constructor since the argument is a reference (It would have if the argument was a "plain" CString).
CString cs;
cs = buf;
log.LogMethod(cs)

Pass an element from C type string array to a COM object as BSTR? (in C++)

I am writing a C++ DLL that is called by an external program.
1.) I take an array of strings (as char *var) as an argument from this program.
2.) I want to iterate through this array and call a COM function on each element of the string array. The COM function must take a BSTR:
DLL_EXPORT(void) runUnitModel(char *rateMaterialTypeNames) {
HRESULT hr = CoInitialize(NULL);
// Create the interface pointer.
IUnitModelPtr pIUnit(__uuidof(BlastFurnaceUnitModel));
pIUnit->initialiseUnitModel();
int i;
for(i=0; i < sizeOfPortRatesArray; i++)
pIUnit->createPort(SysAllocString(BSTR((const char *)rateMaterialTypeNames[i])));
I think its the SysAllocString(BSTR((const char *)rateMaterialTypeNames[i])) bit that is giving me problems. I get an access violation when the programs runs.
Is this the right way to access the value of the rateMaterialTypeName at i? Note I am expecting something like "IronOre" as the value at i, not a single character.
If you're using Microsofts ATL, you can use the CComBSTR class.
It will accept a char* and create a BSTR from it, also, you don't need to worry about deleting the BSTR, all that happens in the dtor for CComBSTR.
Also, see Matthew Xaviers answer, it doesn't look like you're passing your array of strings into that function properly.
Hope this helps
Because a variable holding a C string is just a pointer to the first element (a char*), in order to pass an array of C strings, the parameter to your function should be a char**:
DLL_EXPORT(void) runUnitModel(char **rateMaterialTypeNames)
This way, when you evaluate rateMaterialTypeNames[i], the result will be a char*, which is the parameter type you need to pass to SysAllocString().
Added note: you will also need to convert the strings to wide chars at some point, as Tommy Hui's answer points out.
If the parameter to the function rateMaterialTypeNames is a string, then
rateMaterialTypeNames[i]
is a character and not a string. You should use just the parameter name itself.
In addition, casts in general are bad. The conversion to a BSTR is a big flag. The parameter type for SysAllocString is
const OLECHAR*
which for 32-bit compilers is a wide character. So this will definitely fail because the actual parameter is a char*.
What the code needs is a conversion of narrow string to a wide string.
const OLECHAR* pOleChar = A2COLE( *pChar );
BSTR str = SysAllocString( pOleChar );
// do something with the 'str'
SysFreeString( str ); // need to cleanup the allocated BSTR