[c++] LPCSTR, LPCTSTR and LPTSTR

What the difference between LPCSTR, LPCTSTR and LPTSTR?

Why do we need to do this to convert a string into a LV / _ITEM structure variable pszText:

LV_DISPINFO dispinfo;  
dispinfo.item.pszText = LPTSTR((LPCTSTR)string);

This question is related to c++ windows visual-c++ mfc

The answer is


Adding to John and Tim's answer.

Unless you are coding for Win98, there are only two of the 6+ string types you should be using in your application

  • LPWSTR
  • LPCWSTR

The rest are meant to support ANSI platforms or dual compilations. Those are not as relevant today as they used to be.


8-bit AnsiStrings

  • char: 8-bit character (underlying C/C++ data type)
  • CHAR: alias of char (Windows data type)
  • LPSTR: null-terminated string of CHAR (Long Pointer)
  • LPCSTR: constant null-terminated string of CHAR (Long Pointer Constant)

16-bit UnicodeStrings

  • wchar_t: 16-bit character (underlying C/C++ data type)
  • WCHAR: alias of wchar_t (Windows data type)
  • LPWSTR: null-terminated string of WCHAR (Long Pointer)
  • LPCWSTR: constant null-terminated string of WCHAR (Long Pointer Constant)

depending on UNICODE define

  • TCHAR: alias of WCHAR if UNICODE is defined; otherwise CHAR
  • LPTSTR: null-terminated string of TCHAR (Long Pointer)
  • LPCTSTR: constant null-terminated string of TCHAR (Long Pointer Constant)

So:

Item 8-bit (Ansi) 16-bit (Wide) Varies
character CHAR WCHAR TCHAR
string LPSTR LPWSTR LPTSTR
string (const) LPCSTR LPCWSTR LPCTSTR

Bonus Reading

TCHAR ? Text Char (archive.is)


Why is the default 8-bit codepage called "ANSI"?

From Unicode and Windows XP
by Cathy Wissink
Program Manager, Windows Globalization
Microsoft Corporation
May 2002

Despite the underlying Unicode support on Windows NT 3.1, code page support continued to be necessary for many of the higher-level applications and components included in the system, explaining the pervasive use of the “A” [ANSI] versions of the Win32 APIs rather than the “W” [“wide” or Unicode] versions. (The term “ANSI” as used to signify Windows code pages is a historical reference, but is nowadays a misnomer that continues to persist in the Windows community. The source of this comes from the fact that the Windows code page 1252 was originally based on an ANSI draft, which became ISO Standard 8859-1. However, in adding code points to the range reserved for control codes in the ISO standard, the Windows code page 1252 and subsequent Windows code pages originally based on the ISO 8859-x series deviated from ISO. To this day, it is not uncommon to have the development community, both within and outside of Microsoft, confuse the 8859-1 code page with Windows 1252, as well as see “ANSI” or “A” used to signify Windows code page support.)


Adding to John and Tim's answer.

Unless you are coding for Win98, there are only two of the 6+ string types you should be using in your application

  • LPWSTR
  • LPCWSTR

The rest are meant to support ANSI platforms or dual compilations. Those are not as relevant today as they used to be.


To answer the second part of your question, you need to do things like

LV_DISPINFO dispinfo;  
dispinfo.item.pszText = LPTSTR((LPCTSTR)string);

because MS's LVITEM struct has an LPTSTR, i.e. a mutable T-string pointer, not an LPCTSTR. What you are doing is

1) convert string (a CString at a guess) into an LPCTSTR (which in practise means getting the address of its character buffer as a read-only pointer)

2) convert that read-only pointer into a writeable pointer by casting away its const-ness.

It depends what dispinfo is used for whether or not there is a chance that your ListView call will end up trying to write through that pszText. If it does, this is a potentially very bad thing: after all you were given a read-only pointer and then decided to treat it as writeable: maybe there is a reason it was read-only!

If it is a CString you are working with you have the option to use string.GetBuffer() -- that deliberately gives you a writeable LPTSTR. You then have to remember to call ReleaseBuffer() if the string does get changed. Or you can allocate a local temporary buffer and copy the string into there.

99% of the time this will be unnecessary and treating the LPCTSTR as an LPTSTR will work... but one day, when you least expect it...


8-bit AnsiStrings

  • char: 8-bit character (underlying C/C++ data type)
  • CHAR: alias of char (Windows data type)
  • LPSTR: null-terminated string of CHAR (Long Pointer)
  • LPCSTR: constant null-terminated string of CHAR (Long Pointer Constant)

16-bit UnicodeStrings

  • wchar_t: 16-bit character (underlying C/C++ data type)
  • WCHAR: alias of wchar_t (Windows data type)
  • LPWSTR: null-terminated string of WCHAR (Long Pointer)
  • LPCWSTR: constant null-terminated string of WCHAR (Long Pointer Constant)

depending on UNICODE define

  • TCHAR: alias of WCHAR if UNICODE is defined; otherwise CHAR
  • LPTSTR: null-terminated string of TCHAR (Long Pointer)
  • LPCTSTR: constant null-terminated string of TCHAR (Long Pointer Constant)

So:

Item 8-bit (Ansi) 16-bit (Wide) Varies
character CHAR WCHAR TCHAR
string LPSTR LPWSTR LPTSTR
string (const) LPCSTR LPCWSTR LPCTSTR

Bonus Reading

TCHAR ? Text Char (archive.is)


Why is the default 8-bit codepage called "ANSI"?

From Unicode and Windows XP
by Cathy Wissink
Program Manager, Windows Globalization
Microsoft Corporation
May 2002

Despite the underlying Unicode support on Windows NT 3.1, code page support continued to be necessary for many of the higher-level applications and components included in the system, explaining the pervasive use of the “A” [ANSI] versions of the Win32 APIs rather than the “W” [“wide” or Unicode] versions. (The term “ANSI” as used to signify Windows code pages is a historical reference, but is nowadays a misnomer that continues to persist in the Windows community. The source of this comes from the fact that the Windows code page 1252 was originally based on an ANSI draft, which became ISO Standard 8859-1. However, in adding code points to the range reserved for control codes in the ISO standard, the Windows code page 1252 and subsequent Windows code pages originally based on the ISO 8859-x series deviated from ISO. To this day, it is not uncommon to have the development community, both within and outside of Microsoft, confuse the 8859-1 code page with Windows 1252, as well as see “ANSI” or “A” used to signify Windows code page support.)


Quick and dirty:

LP == Long Pointer. Just think pointer or char*

C = Const, in this case, I think they mean the character string is a const, not the pointer being const.

STR is string

the T is for a wide character or char (TCHAR) depending on compile options.


The short answer to 2nd part of the question is simply that CString class doesn't provide a direct typecast conversion by design and what you are doing is kind of cheat.

A longer answer is the following:

The reason you can typcast CString to LPCTSTR is because CString provides this facility by overriding operator=. By design it provides conversion to only LPCTSTR pointer so the string value can't be modified with this pointer.

In other words, it simply doesn't provide an overload operator= to convert the CString into LPSTR for the same reason as above. They don't want to allow altering the string value this way.

So essentially, the trick is to use the operator CString provide and get this:

LPTSTR lptstr = (LPCTSTR) string; // CString provide this operator overload

Now LPTSTR can be further type casted to LPSTR :)

dispinfo.item.pszText = LPTSTR( lpfzfd); // accomplish the cheat :P

The correct way to get LPTSTR from 'CString' is this though (complete example):

CString str = _T("Hello");
LPTSTR lpstr = str.GetBuffer(str.GetAllocLength());
str.ReleaseBuffer(); // you must call this function if you change the string above with the pointer

Again because the GetBuffer() returns LPTSTR for that reason that now you can modify :)


To answer the second part of your question, you need to do things like

LV_DISPINFO dispinfo;  
dispinfo.item.pszText = LPTSTR((LPCTSTR)string);

because MS's LVITEM struct has an LPTSTR, i.e. a mutable T-string pointer, not an LPCTSTR. What you are doing is

1) convert string (a CString at a guess) into an LPCTSTR (which in practise means getting the address of its character buffer as a read-only pointer)

2) convert that read-only pointer into a writeable pointer by casting away its const-ness.

It depends what dispinfo is used for whether or not there is a chance that your ListView call will end up trying to write through that pszText. If it does, this is a potentially very bad thing: after all you were given a read-only pointer and then decided to treat it as writeable: maybe there is a reason it was read-only!

If it is a CString you are working with you have the option to use string.GetBuffer() -- that deliberately gives you a writeable LPTSTR. You then have to remember to call ReleaseBuffer() if the string does get changed. Or you can allocate a local temporary buffer and copy the string into there.

99% of the time this will be unnecessary and treating the LPCTSTR as an LPTSTR will work... but one day, when you least expect it...


Quick and dirty:

LP == Long Pointer. Just think pointer or char*

C = Const, in this case, I think they mean the character string is a const, not the pointer being const.

STR is string

the T is for a wide character or char (TCHAR) depending on compile options.


Quick and dirty:

LP == Long Pointer. Just think pointer or char*

C = Const, in this case, I think they mean the character string is a const, not the pointer being const.

STR is string

the T is for a wide character or char (TCHAR) depending on compile options.


Adding to John and Tim's answer.

Unless you are coding for Win98, there are only two of the 6+ string types you should be using in your application

  • LPWSTR
  • LPCWSTR

The rest are meant to support ANSI platforms or dual compilations. Those are not as relevant today as they used to be.


The short answer to 2nd part of the question is simply that CString class doesn't provide a direct typecast conversion by design and what you are doing is kind of cheat.

A longer answer is the following:

The reason you can typcast CString to LPCTSTR is because CString provides this facility by overriding operator=. By design it provides conversion to only LPCTSTR pointer so the string value can't be modified with this pointer.

In other words, it simply doesn't provide an overload operator= to convert the CString into LPSTR for the same reason as above. They don't want to allow altering the string value this way.

So essentially, the trick is to use the operator CString provide and get this:

LPTSTR lptstr = (LPCTSTR) string; // CString provide this operator overload

Now LPTSTR can be further type casted to LPSTR :)

dispinfo.item.pszText = LPTSTR( lpfzfd); // accomplish the cheat :P

The correct way to get LPTSTR from 'CString' is this though (complete example):

CString str = _T("Hello");
LPTSTR lpstr = str.GetBuffer(str.GetAllocLength());
str.ReleaseBuffer(); // you must call this function if you change the string above with the pointer

Again because the GetBuffer() returns LPTSTR for that reason that now you can modify :)


Adding to John and Tim's answer.

Unless you are coding for Win98, there are only two of the 6+ string types you should be using in your application

  • LPWSTR
  • LPCWSTR

The rest are meant to support ANSI platforms or dual compilations. Those are not as relevant today as they used to be.


Quick and dirty:

LP == Long Pointer. Just think pointer or char*

C = Const, in this case, I think they mean the character string is a const, not the pointer being const.

STR is string

the T is for a wide character or char (TCHAR) depending on compile options.


Examples related to c++

Method Call Chaining; returning a pointer vs a reference? How can I tell if an algorithm is efficient? Difference between opening a file in binary vs text How can compare-and-swap be used for a wait-free mutual exclusion for any shared data structure? Install Qt on Ubuntu #include errors detected in vscode Cannot open include file: 'stdio.h' - Visual Studio Community 2017 - C++ Error How to fix the error "Windows SDK version 8.1" was not found? Visual Studio 2017 errors on standard headers How do I check if a Key is pressed on C++

Examples related to windows

"Permission Denied" trying to run Python on Windows 10 A fatal error occurred while creating a TLS client credential. The internal error state is 10013 How to install OpenJDK 11 on Windows? I can't install pyaudio on Windows? How to solve "error: Microsoft Visual C++ 14.0 is required."? git clone: Authentication failed for <URL> How to avoid the "Windows Defender SmartScreen prevented an unrecognized app from starting warning" XCOPY: Overwrite all without prompt in BATCH Laravel 5 show ErrorException file_put_contents failed to open stream: No such file or directory how to open Jupyter notebook in chrome on windows Tensorflow import error: No module named 'tensorflow'

Examples related to visual-c++

How to install Visual C++ Build tools? Microsoft Visual C++ 14.0 is required (Unable to find vcvarsall.bat) How to install numpy on windows using pip install? How to use _CRT_SECURE_NO_WARNINGS How to play or open *.mp3 or *.wav sound file in c++ program? What is C# equivalent of <map> in C++? The program can't start because MSVCR110.dll is missing from your computer error LNK2038: mismatch detected for '_MSC_VER': value '1600' doesn't match value '1700' in CppFile1.obj Identifier is undefined error LNK2001: unresolved external symbol (C++)

Examples related to mfc

How can I convert an Int to a CString? Convert MFC CString to integer Convert CString to const char* LPCSTR, LPCTSTR and LPTSTR How do you convert CString and std::string std::wstring to each other?