Is CString really based on TCHAR?
-
Hi. I wrote a simiral question before but I feel like I am still confused. I am compiling in Unicode and I know that in Unicode circumstance CString is allocated with TCHAR as you see below.
typedef ATL::CStringT< TCHAR, StrTraitMFC_DLL< TCHAR > > CString;
So obviously CString has nothing to do with LPCTSTR, which is const char *, or any other type, but TCHAR. However, when I try to do this code below it occurs an error.
CString _str = TEXT("ABCD");
TCHAR* _tstr = _str;The correct version of the code above should be like this.
CString _str = TEXT("ABCD");
TCHAR* _tstr = (TCHAR*)(LPCTSTR)_str;There are two type castings, to LPCTSTR and then to TCHAR*, even though CString is defined with TCHAR type. I'd like to know why this weird conversion happens from the operator overloading's view of CStringT, and CSimpleStringT and also the template structure of all the classes related to CString. If I am asking too much to answer in a few sentences, any web pages' link that explain this will be appreciated. Thanks in advance!
-
Hi. I wrote a simiral question before but I feel like I am still confused. I am compiling in Unicode and I know that in Unicode circumstance CString is allocated with TCHAR as you see below.
typedef ATL::CStringT< TCHAR, StrTraitMFC_DLL< TCHAR > > CString;
So obviously CString has nothing to do with LPCTSTR, which is const char *, or any other type, but TCHAR. However, when I try to do this code below it occurs an error.
CString _str = TEXT("ABCD");
TCHAR* _tstr = _str;The correct version of the code above should be like this.
CString _str = TEXT("ABCD");
TCHAR* _tstr = (TCHAR*)(LPCTSTR)_str;There are two type castings, to LPCTSTR and then to TCHAR*, even though CString is defined with TCHAR type. I'd like to know why this weird conversion happens from the operator overloading's view of CStringT, and CSimpleStringT and also the template structure of all the classes related to CString. If I am asking too much to answer in a few sentences, any web pages' link that explain this will be appreciated. Thanks in advance!
Dean Seo wrote:
CString _str = TEXT("ABCD"); TCHAR* _tstr = _str;
That's not acceptable.
_tstr
is a pointer to achar
(orwchar_t
based on your build). But,_str
is aCString
variable and so, this conversion won't work.Dean Seo wrote:
CString _str = TEXT("ABCD"); TCHAR* _tstr = (TCHAR*)(LPCTSTR)_str;
That's not a good thing to do either.
LP**C**TSTR
(with the added C in between means that it's aconst
). By explicitly casting it to aTCHAR*
, you're casting theconst
away and then you are assigning it to aTCHAR*
later. Remember thatCString
is a C++ class. It uses a string (achar*
or awchar_t*
) internally to store the contents, but it does a lot of other things as well. If you really need to acquire a pointer to the location where the class is storing the string, then there's this CString::GetBuffer()[^] method. There are some quirks associated with this method though, and you need to exercise caution while using it. If you call it, you want to make sure that you call CString::ReleaseBuffer()[^] immediately after you're done with the buffer. If you don't know what that means, you don't want to use that method. I strongly recommend that you read the following essays: The Complete Guide to C++ Strings, Part I - Win32 Character Encodings[^] The Complete Guide to C++ Strings, Part II - String Wrapper Classes[^] CString Management[^] -
Dean Seo wrote:
CString _str = TEXT("ABCD"); TCHAR* _tstr = _str;
That's not acceptable.
_tstr
is a pointer to achar
(orwchar_t
based on your build). But,_str
is aCString
variable and so, this conversion won't work.Dean Seo wrote:
CString _str = TEXT("ABCD"); TCHAR* _tstr = (TCHAR*)(LPCTSTR)_str;
That's not a good thing to do either.
LP**C**TSTR
(with the added C in between means that it's aconst
). By explicitly casting it to aTCHAR*
, you're casting theconst
away and then you are assigning it to aTCHAR*
later. Remember thatCString
is a C++ class. It uses a string (achar*
or awchar_t*
) internally to store the contents, but it does a lot of other things as well. If you really need to acquire a pointer to the location where the class is storing the string, then there's this CString::GetBuffer()[^] method. There are some quirks associated with this method though, and you need to exercise caution while using it. If you call it, you want to make sure that you call CString::ReleaseBuffer()[^] immediately after you're done with the buffer. If you don't know what that means, you don't want to use that method. I strongly recommend that you read the following essays: The Complete Guide to C++ Strings, Part I - Win32 Character Encodings[^] The Complete Guide to C++ Strings, Part II - String Wrapper Classes[^] CString Management[^]Hi, good to see you again.
Rajesh R Subramanian wrote:
That's not acceptable.
_tstr
is a pointer to achar
(orwchar_t
based on your build). But,_str
is aCString
variable and so, this conversion won't work.CString is a class using a wchar_t* to store the contents, and TCHAR is wchar_t. CSimpleStringT has "operator PCXSTR();", and PCXSTR in Unicode circumstance means LPCWSTR which is also wchar_t*. So if CSTring uses wchar_t and has a perfect method(operator PCXSTR()) to return wchar_t type, why can't I get it using TCHAR* (which is also wchar_t*) I think at least this code below has to work, whether it is safe to use or not.
CString _str = TEXT("ABCD");
TCHAR* _tstr = (TCHAR*)_str;Thank you for helping me this time again by the way.
-
Hi, good to see you again.
Rajesh R Subramanian wrote:
That's not acceptable.
_tstr
is a pointer to achar
(orwchar_t
based on your build). But,_str
is aCString
variable and so, this conversion won't work.CString is a class using a wchar_t* to store the contents, and TCHAR is wchar_t. CSimpleStringT has "operator PCXSTR();", and PCXSTR in Unicode circumstance means LPCWSTR which is also wchar_t*. So if CSTring uses wchar_t and has a perfect method(operator PCXSTR()) to return wchar_t type, why can't I get it using TCHAR* (which is also wchar_t*) I think at least this code below has to work, whether it is safe to use or not.
CString _str = TEXT("ABCD");
TCHAR* _tstr = (TCHAR*)_str;Thank you for helping me this time again by the way.
Dean Seo wrote:
LPCWSTR which is also wchar_t*.
No, it is not.
LPCWSTR
is**const** wchar_t*
and the added "const
" has its significance!Dean Seo wrote:
I think at least this code below has to work, whether it is safe to use or not.
CString _str = TEXT("ABCD");
TCHAR* _tstr = (TCHAR*)_str;That code may compile, but it may or may not work depending on what you intend to do with the
_tstr
variable. If you use the pointer to modify the contents it's pointing to, then you'll be in trouble, because you promisedCString
not to modify the contents stored in the pointer that it returned ("const
", remember?). I'm happy to answer your questions, but before you jump into anything further, I recommend that you read the 3 articles I linked you to, and that will clear up a lot of your doubts."Real men drive manual transmission" - Rajesh.
-
Dean Seo wrote:
LPCWSTR which is also wchar_t*.
No, it is not.
LPCWSTR
is**const** wchar_t*
and the added "const
" has its significance!Dean Seo wrote:
I think at least this code below has to work, whether it is safe to use or not.
CString _str = TEXT("ABCD");
TCHAR* _tstr = (TCHAR*)_str;That code may compile, but it may or may not work depending on what you intend to do with the
_tstr
variable. If you use the pointer to modify the contents it's pointing to, then you'll be in trouble, because you promisedCString
not to modify the contents stored in the pointer that it returned ("const
", remember?). I'm happy to answer your questions, but before you jump into anything further, I recommend that you read the 3 articles I linked you to, and that will clear up a lot of your doubts."Real men drive manual transmission" - Rajesh.
Rajesh R Subramanian wrote:
I recommend that you read the 3 articles I linked you to, and that will clear up a lot of your doubts.
I read those 3 articles all the way through and it did help. Thank you. I will print out those articles and read again anytime I need.
Rajesh R Subramanian wrote:
That code may compile, but it may or may not work depending on what you intend to do with the
_tstr
variable.By the way, in that case, the thing is that that code doesn't even comfile and it occurs an 'casting failed' error. So I just made a simple example that claify why this happens.
class A{
public:
// I didn't allocate any block of memory on m_WideCharacter to make it simpler.
const wchar_t* m_WideCharacter;operator const wchar\_t\*() const{ return m\_WideCharacter; }
};
int _tmain(int argc, _TCHAR* argv[])
{
A aaa;
wchar_t* _WideCharacter = aaa; // error-the operator method can't be called.
wchar_t* _WideCharacter = (wchar_t*)aaa // error-the operator method can't be called.
wchar_t* _WideCharacter = (wchar_t*)(const wchar_t*)aaa // works!
return 0;
}I think I just misunderstood how const and operator() that returns const value in C++ works. To make operator const wchar_t*() const return the value, we definitely need the type casting (const wchar_t*) first, otherwise the compiler wouldn't understand if the operator method in class A can be possibly called. And that is what (const wchar_t*) is for. That's it. That is why in that MFC based code I need to write (LPCTSTR*) because CString only has operator PCXSTR(), which is the same as operaotr const wchar_t*(), and the only way that the operator PCXSTR() is called is to write (LPCTSTR*) for type casting. Am I correct? Or am I not clear enough???
modified on Friday, July 29, 2011 1:52 AM
-
Rajesh R Subramanian wrote:
I recommend that you read the 3 articles I linked you to, and that will clear up a lot of your doubts.
I read those 3 articles all the way through and it did help. Thank you. I will print out those articles and read again anytime I need.
Rajesh R Subramanian wrote:
That code may compile, but it may or may not work depending on what you intend to do with the
_tstr
variable.By the way, in that case, the thing is that that code doesn't even comfile and it occurs an 'casting failed' error. So I just made a simple example that claify why this happens.
class A{
public:
// I didn't allocate any block of memory on m_WideCharacter to make it simpler.
const wchar_t* m_WideCharacter;operator const wchar\_t\*() const{ return m\_WideCharacter; }
};
int _tmain(int argc, _TCHAR* argv[])
{
A aaa;
wchar_t* _WideCharacter = aaa; // error-the operator method can't be called.
wchar_t* _WideCharacter = (wchar_t*)aaa // error-the operator method can't be called.
wchar_t* _WideCharacter = (wchar_t*)(const wchar_t*)aaa // works!
return 0;
}I think I just misunderstood how const and operator() that returns const value in C++ works. To make operator const wchar_t*() const return the value, we definitely need the type casting (const wchar_t*) first, otherwise the compiler wouldn't understand if the operator method in class A can be possibly called. And that is what (const wchar_t*) is for. That's it. That is why in that MFC based code I need to write (LPCTSTR*) because CString only has operator PCXSTR(), which is the same as operaotr const wchar_t*(), and the only way that the operator PCXSTR() is called is to write (LPCTSTR*) for type casting. Am I correct? Or am I not clear enough???
modified on Friday, July 29, 2011 1:52 AM
Dean Seo wrote:
By the way, in that case, the thing is that that code doesn't even comfile and it occurs an 'casting failed' error.
I overlooked it to assume that you did a double casting to take the const away. That is a common thing (a terrible thing, actually) that people do:
CString _str = TEXT("ABCD");
TCHAR* _tstr = (LPTSTR)(LPCTSTR)_str; //Using the LPCTSTR operator to get the pointer, and then casting the const away. A bad thing to do.Dean Seo wrote:
wchar_t* _WideCharacter = (wchar_t*)(const wchar_t*)aaa // works!
You shouldn't say "works!". You should instead say "it compiles!". Yeah, it will compile. But it's a terrible thing to do. How about this instead?
A aaa;
const wchar_t* p = aaa;There are several APIs (and functions that we may code) that will need a read-only string. For example, you may write a function that takes the path of a file and encrypts it. So, you'll just be accepting the string which will be the path, and you'll not be modifying the string itself. In cases like that (and in MOST cases), you will only need a read-only string. That's why
CString
gives you aLPCTSTR
(const wchar_t*
), which will be pointing to the internal buffer whereCString
is storing the string. But there are those edge cases where might want to have direct write access to the internal buffer ofCString
. For such cases,CString
provides theGetBuffer()
method (which I already explained). Conclusively, there is no excuse for abusing theLPCTSTR
operator (using it to cast theconst
away and assigning it to a non-const variable is bad)."Real men drive manual transmission" - Rajesh.
-
Rajesh R Subramanian wrote:
I recommend that you read the 3 articles I linked you to, and that will clear up a lot of your doubts.
I read those 3 articles all the way through and it did help. Thank you. I will print out those articles and read again anytime I need.
Rajesh R Subramanian wrote:
That code may compile, but it may or may not work depending on what you intend to do with the
_tstr
variable.By the way, in that case, the thing is that that code doesn't even comfile and it occurs an 'casting failed' error. So I just made a simple example that claify why this happens.
class A{
public:
// I didn't allocate any block of memory on m_WideCharacter to make it simpler.
const wchar_t* m_WideCharacter;operator const wchar\_t\*() const{ return m\_WideCharacter; }
};
int _tmain(int argc, _TCHAR* argv[])
{
A aaa;
wchar_t* _WideCharacter = aaa; // error-the operator method can't be called.
wchar_t* _WideCharacter = (wchar_t*)aaa // error-the operator method can't be called.
wchar_t* _WideCharacter = (wchar_t*)(const wchar_t*)aaa // works!
return 0;
}I think I just misunderstood how const and operator() that returns const value in C++ works. To make operator const wchar_t*() const return the value, we definitely need the type casting (const wchar_t*) first, otherwise the compiler wouldn't understand if the operator method in class A can be possibly called. And that is what (const wchar_t*) is for. That's it. That is why in that MFC based code I need to write (LPCTSTR*) because CString only has operator PCXSTR(), which is the same as operaotr const wchar_t*(), and the only way that the operator PCXSTR() is called is to write (LPCTSTR*) for type casting. Am I correct? Or am I not clear enough???
modified on Friday, July 29, 2011 1:52 AM
Dean, let me know if you need any further explanation.
"Real men drive manual transmission" - Rajesh.
-
Dean, let me know if you need any further explanation.
"Real men drive manual transmission" - Rajesh.
-
I am sorry for this late response. Thank you for helping me. You are the best! Thank you again.
You're welcome.
Dean Seo wrote:
You are the best!
Now, you're overselling me. :-O
"Real men drive manual transmission" - Rajesh.