Is a CString always null-terminated?

7.2k Views Asked by At

From the CString interface, clearly one should not assume that a CString is null-terminated. However, it seems that sometimes there is, in fact, a null character at the end of the string. Is it possible, in the Windows implementation, to create a CString that does not have a null character, so that reading one character past the end of the string is looking at a different heap object?

4

There are 4 best solutions below

0
On

Look at the MSDN documentation here:

http://msdn.microsoft.com/es-es/library/awkwbzyc(v=vs.80).aspx

Based on that I would guess there is a null terminator there you just have to do some casting to get it.

0
On

A CString is more like a Visual Basic string or a BSTR. It can contain embedded binary zeros in the data portion of the CString. However when using the various operators to convert between the CString and standard C type zero terminated strings, an embedded binary zero is treated like an end of string character. So a CString is a lot like a BSTR type of variable.

For instance I put the following source lines into an MFC project and ran it in the Visual Studio C++ debugger.

CString myString (_T("this\000is a String."));  // myString will only contain "this" as a zero terminated string.

CString myJJ;
myJJ.Format (_T("this%cisaxxx"), 0);   // this creates a string with an embedded binary zero in it.
int iLen = myJJ.GetLength();      // this returns the length of the complete string, 11 characters
CString myRight = myJJ.Right(4);  // this returns the right most 4 characters, "axxx"
TCHAR  myTbuff[64];
_tcscpy (myTbuff, myJJ);    // this copies the string up to the embedded binary zero into myTbuff

As far as going to the next heap object, I would not depend on that. It is up to the implementation of CString as to how the object is laid out in memory and how it is using memory. It may be that if you create a CString, a buffer sized for 64 characters is allocated regardless of how few characters you put into it. CString provides the GetLength() method to find out how many characters are in the CString so that should be used. There are also methods for getting and setting specific character positions.

CString was designed to allow the programmer to think in terms of strings as in Visual Basic types of strings rather than having to deal with C style strings that are really arrays of characters with a special end of string terminator character, the binary zero.

Edit01 - Compiler arguments and effects on CString

The Visual Studio compilers previous to Visual Studio 2013 allowed the CString class to create either 8 bit Multi-Byte Character Set or 16 bit UNICODE character strings depending on whether _MBCS or _UNICODE was defined when processing the source file.

The reason I say previous to Visual Studio 2013 is that it appears that using _MBCS is now deprecated (see also Side-effect of deprecation of MBCS support for MFC in VS 2013).

The root of this flexibility is the TCHAR definition which may be either char if _MBCS is defined or wchar_t if _UNICODE is defined. This in turn determines what happens with the _T() or TEXT() macro which will turn a quoted string into either an array of type char or an array of type wchar_t by either pre-pending or not the L used to indicate a wchar_t text string. This also influences the actual type of an LPCTSTR (pointer to a const TCHAR string) or LPTSTR (pointer to a non-const TCHAR string).

Windows 95/98/ME did not have native support for UNICODE in the Windows API as did Windows NT/2000/XP so allowing the choice of UNICODE to target Windows NT or MBCS to target Windows 95 was helpful. Another option at the time was the Microsoft Layer for Unicode that provided a UNICODE interface to the Windows API for Windows 95/98/ME.

0
On

Yes, the CString is always null terminated.

The documentation states that the you can cast a CString to LPCTSTR, and LPCTSTR is a typedef to one of:
__nullterminated CONST WCHAR *
__nullterminated CONST CHAR *
depending on whether UNICODE is defined or not.

0
On

The cast to LPCTSTR will provide a null-terminated string, but there's no guarantee that the string is null terminated before that conversion. It could easily terminate the string inside the function.

The source of CString is provided by Microsoft, the best way to make sure is to look there and see exactly how things are implemented. Of course it could always change in the next version - CString has had quite a few changes over the years.