Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using CString object in CString::Format

Tags:

c++

mfc

Can I use CString in CString::Format as follows:

CString text = _T("text");
CString format;
format.Format(_T("%s"), text);

The same method is seen in MFC source files and MFC books. For example:

//From MFC file:
//C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\atlmfc\src\mfc\
//    afxeditbrowsectrl.cpp
BOOL CMFCEditBrowseCtrl::OnIllegalFileName(CString& strFileName)
{
    CString strError;
    CString strMessage;
    ...
    strMessage.Format(_T("%Ts\r\n%Ts"), strFileName, strError);
    //I don't know what is the `T` in `"%Ts"` !
    ...
}

Yet, other MFC source files use LPCTSTR cast. Example:

format.Format(_T("%s"), (LPCTSTR)text);

Is the cast mandatory?

like image 911
Barmak Shemirani Avatar asked Jul 20 '26 17:07

Barmak Shemirani


2 Answers

From the documentation of the CStringT class template:

You can freely substitute CStringT objects for PCXSTR function arguments.

Whenever a function parameter expects a constant C-style string, you can pass a CStringT object, that is implicitly converted by invoking the operator PCXSTR().

A function with variadic arguments, on the other hand, takes an untyped list of arguments. In this scenario, passing a CStringT object where a PCXSTR is (semantically) expected, is not safe. The compiler has no means of knowing, that it should emit code to perform the implicit conversion. You are responsible for performing the conversion yourself, either by invoking operator PCXSTR(), or by calling the GetString() class member.

This is as far as the documented contract goes. To understand why it is still (technically) safe to pass a CStringT through a variadic argument list, it helps to take a look at the implementation1:

The CSimpleStringT class template is the base for all supported string classes. It contains a single (private) data member of type PCXSTR, and no virtual functions, making it a standard layout type. The binary representation is thus identical to that of its only member, a pointer to a zero-terminated array of characters.


Unrelated to the discussion of this Q&A, yet for completeness' sake, here is a brief explanation, of how the CSimpleStringT keeps track of the additional data (like string length or reference count). The only data member m_pszData points into a structure of type CStringData, that consists of an initial sequence of constant size, storing the bookkeeping information, immediately followed by an array of characters of length nAllocLength + 1. m_pszData points at this array, and the additional data is retrieved through pointer arithmetic, as implemented by the private GetData() member:

CStringData* GetData() const throw()
{
    return( reinterpret_cast< CStringData* >( m_pszData )-1 );
}

The class layout is summarized in the following diagram:

                        +------------------------+
                        | CStringData            |
                        +========================+
                        | pStringMgr             |
+----------------+      | nDataLength            |
| CSimpleStringT |      | nAllocLength           |
+================+      | nRefs                  |
| m_pszData      | ---> | data[0]                |
+----------------+      | data[1]                |
                        . ...                    .
                        | data[nAllocLength - 1] |
                        | data[nAllocLength]     |
                        +------------------------+

1 This is based on the implementation that ships with Visual Studio 2017, that can - in theory - change without prior notice.

like image 70
IInspectable Avatar answered Jul 23 '26 08:07

IInspectable


If you don't use the cast, you're passing the CString object by value. That just happens to work because of the way CString is implemented, and there is no guarantee that the CString implementation will never change.

like image 34
Sid S Avatar answered Jul 23 '26 08:07

Sid S



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!