LPCSTR, LPCTSTR и LPTSTR

В чем разница между LPCSTR, LPCTSTR и LPTSTR?

Почему нам нужно это сделать, чтобы преобразовать строку в переменную структуры LV / _ITEM pszText:

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

person nothingMaster    schedule 26.11.2008    source источник
comment
Не могли бы вы точно сказать, что такое строка типа? (например, CString)   -  person John Sibly    schedule 26.11.2008


Ответы (6)


Чтобы ответить на первую часть вашего вопроса:

LPCSTR - указатель на константную строку (LP означает длинный указатель)

LPCTSTR - указатель на const TCHAR строку (TCHAR является либо широким символом, либо символом, в зависимости от того, определен ли UNICODE в вашем проекте)

LPTSTR - указатель на (неконстантную) TCHAR строку

На практике, когда мы говорили об этом в прошлом, мы для простоты опускали фразу «указатель на», но, как упоминалось в lightness-races-in-orbit, все они являются указателями.

Это отличная статья codeproject, описывающая строки C ++ (см. 2/3 пути вниз для диаграммы, сравнивающей различные типы)

person John Sibly    schedule 26.11.2008
comment
Я быстро просмотрел эту статью - кажется отличной, добавляю ее в свои закладки и прочту, как только у меня будет время. - person nothingMaster; 26.11.2008
comment
Все неправильно. Все это не струны. Все они указатели. -1 - person Lightness Races in Orbit; 28.05.2015
comment
@LightnessRacesinOrbit Вы технически правы - хотя, по моему опыту, это обычная практика, чтобы не указывать указатель на .... описание для краткости при обращении к строковым типам в C ++. - person John Sibly; 04.06.2015
comment
@JohnSible: В C, да. В C ++ этого быть не должно! - person Lightness Races in Orbit; 04.06.2015
comment
Обратите внимание, что эта статья codeproject была написана 15 лет назад и, если она не будет обновлена, содержит вводящие в заблуждение предположения о том, что символы Unicode всегда составляют 2 байта. Это совершенно неверно. Даже UTF16 имеет переменную длину ... гораздо лучше сказать, что широкие символы имеют кодировку UCS-2, и что Unicode в этом контексте относится к UCS-2. - person u8it; 13.10.2017
comment
Это беспорядок, символы Unicode изначально должны были состоять из двух байтов, но этого оказалось недостаточно. Итак, UTF-16 был разработан для внедрения современного юникода в системы, которые изначально были разработаны для 16-битного юникода. В современных окнах широкая строка на самом деле представляет собой последовательность кодовых единиц UTF-16. - person plugwash; 01.02.2019
comment
Конечно, персонажи за пределами основного многоязычного плана довольно редки, поэтому в большинстве случаев вы можете игнорировать эту деталь. - person plugwash; 01.02.2019
comment
Хм ... в этом случае, @LightnessRacesinOrbit, я бы добавил добавление, что можно не указывать указатель на ... при обращении к C-строкам в C ++, если и только если ссылаются конкретно на (распался ) строковых литералов или при взаимодействии / работе с кодом, написанным на C, полагается на типы C вместо типов C ++ и / или имеет связь с C через extern "C". Кроме того, да, ему определенно понадобится либо бит указателя, либо конкретное описание в виде строки C. - person Justin Time - Reinstate Monica; 11.09.2019

Быстро и грязно:

LP == L ong ​​P ointer. Подумайте только о указателе или символе *

C = C onst, в этом случае, я думаю, они означают, что символьная строка является константой, а не указателем, являющимся константой.

STR - это строка

T предназначен для широкого символа или символа (TCHAR) в зависимости от параметров компиляции.

person Tim    schedule 26.11.2008
comment
T не для широких символов, это для различных типов символов. W означает широкий (как в WCHAR). Если определен UNICODE, TCHAR == WCHAR, иначе TCHAR == CHAR. Итак, если UNICODE не определен, LPCTSTR == LPCSTR. - person jalf; 26.11.2008
comment
поэтому я написал в зависимости от параметров компиляции - person Tim; 26.11.2008
comment
Мне очень нравятся такие объяснения :). Огромное спасибо - person Dzung Nguyen; 19.03.2010
comment
@jalf, Так что же означает T? - person Pacerier; 14.05.2015
comment
@Pacerier Я не уверен. Шаблон или Тип, возможно? - person jalf; 14.05.2015
comment
определенно не шаблон и не тип. codeproject.com/Articles/76252/ - person Tim; 16.05.2015
comment
T означает T ext - person Ian Boyd; 27.06.2018

8-битные строки AnsiStrings

  • char: 8-битный символ (базовый тип данных C / C ++)
  • CHAR: псевдоним char (тип данных Windows)
  • LPSTR: строка с нулевым символом в конце CHAR (L ong ​​P ointer)
  • LPCSTR: константная строка с завершающим нулем для CHAR (L ong ​​P ointer C onstant)

16-битные UnicodeStrings

  • wchar_t: 16-битный символ (базовый тип данных C / C ++)
  • WCHAR: псевдоним wchar_t (тип данных Windows)
  • LPWSTR: строка с нулевым символом в конце WCHAR (L ong ​​P ointer)
  • LPCWSTR: константная строка с завершающим нулем для WCHAR (L ong ​​P ointer C onstant)

в зависимости от UNICODE определить

  • TCHAR: псевдоним WCHAR, если определен UNICODE; в противном случае CHAR
  • LPTSTR: строка с нулевым символом в конце TCHAR (L ong ​​P ointer)
  • LPCTSTR: константная строка с завершающим нулем для TCHAR (L ong ​​P ointer C onstant)

So:

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

Бонусное чтение

TCHARText Char (archive.is)


Почему 8-битная кодовая страница по умолчанию называется ANSI?

Из Unicode и Windows XP
Кэти Виссинк.
Менеджер программы, Глобализация Windows
Корпорация Microsoft
Май 2002 г.

Несмотря на лежащую в основе поддержку Unicode в Windows NT 3.1, поддержка кодовых страниц по-прежнему необходима для многих приложений и компонентов более высокого уровня, включенных в систему, что скорее объясняет повсеместное использование версий A [ANSI] интерфейсов API Win32. чем версии «W» [«широкий» или Unicode]. (Термин «ANSI», используемый для обозначения кодовых страниц Windows, является исторической справкой, но в настоящее время это неправильное название, которое продолжает сохраняться в сообществе Windows. Источником этого является тот факт, что кодовая страница Windows 1252 изначально была основана на черновик ANSI, который стал стандартом ISO 8859-1. Однако при добавлении кодовых точек к диапазону, зарезервированному для управляющих кодов в стандарте ISO, кодовая страница Windows 1252 и последующие кодовые страницы Windows, первоначально основанные на серии ISO 8859-x, отклонились из ISO. По сей день нередко сообщества разработчиков, как внутри, так и за пределами Microsoft, путают кодовую страницу 8859-1 с Windows 1252, а также видят «ANSI» или «A», используемые для обозначения Windows поддержка кодовой страницы.)

person Ian Boyd    schedule 27.09.2017
comment
Жаль, что этот ответ никогда не дойдет до вершины, потому что он такой новый ... это действительно то, что SO необходимо исправить. На сегодняшний день это лучший ответ. - person Dan Bechard; 04.04.2018
comment
Это действительно очень помогает мне, когда я работаю над проектом Unicode. Спасибо! - person Yoon5oo; 27.06.2018
comment
Хороший ответ. Я думаю, стоит добавить, что версия Unicode использует UTF16, поэтому каждый 16-битный фрагмент является не символом, а единицей кода. Имена исторические (когда Unicode === UCS2). - person Margaret Bloom; 29.01.2019

Добавление к ответу Джона и Тима.

Если вы не пишете код для Win98, есть только два из 6+ строковых типов, которые вы должны использовать в своем приложении.

  • LPWSTR
  • LPCWSTR

Остальные предназначены для поддержки платформ ANSI или двойной компиляции. Сегодня это уже не так актуально, как раньше.

person JaredPar    schedule 26.11.2008
comment
@BlueRaja, в своем ответе я в основном имел в виду строки на основе C. Но для C ++ я бы избегал std::string, потому что это все еще строка на основе ASCII, и предпочел бы вместо этого std::wstring. - person JaredPar; 12.05.2010
comment
Вам следует использовать LPTSTR и LPCTSTR, если вы не вызываете версии функций в формате ASCII (* A) или widechar (* W) напрямую. Это псевдонимы любой ширины символа, которую вы укажете при компиляции. - person osvein; 28.06.2017
comment
... И теперь, когда Microsoft работает над совместимостью *A версий WinAPI с кодовой страницей UTF-8, они внезапно стали намного более актуальными. ;П - person Justin Time - Reinstate Monica; 13.09.2019

Чтобы ответить на вторую часть вашего вопроса, вам нужно сделать такие вещи, как

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

потому что структура MS LVITEM имеет LPTSTR, то есть изменяемый указатель T-строки, а не LPCTSTR. Что ты делаешь

1) преобразовать string (CString в предположении) в LPCTSTR (что на практике означает получение адреса его символьного буфера в виде указателя только для чтения)

2) преобразовать этот доступный только для чтения указатель в записываемый указатель, отбросив его const-сущность.

Это зависит от того, для чего dispinfo используется, есть ли вероятность, что ваш ListView вызов в конечном итоге попытается записать через этот pszText. Если да, то это потенциально очень плохо: в конце концов, вам дали указатель только для чтения, а затем вы решили рассматривать его как доступный для записи: возможно, есть причина, по которой он был доступен только для чтения!

Если это CString, с которым вы работаете, у вас есть возможность использовать string.GetBuffer(), что намеренно дает вам доступный для записи LPTSTR. Затем вы должны не забыть вызвать ReleaseBuffer(), если строка действительно изменилась. Или вы можете выделить локальный временный буфер и скопировать туда строку.

В 99% случаев в этом нет необходимости, и обращение с LPCTSTR как с LPTSTR будет работать ... но однажды, когда вы меньше всего этого ожидаете ...

person AAT    schedule 05.09.2011
comment
Вам следует избегать приведения в стиле C и вместо этого использовать xxx_cast<>(). - person harper; 27.06.2018
comment
@harper Вы совершенно правы, но я цитировал OP, это код, о котором он спрашивал. Если бы я написал код сам, он бы наверняка использовал xxx_cast<> вместо того, чтобы смешивать два разных стиля кастинга на основе скобок! - person AAT; 12.10.2018

Краткий ответ на вторую часть вопроса заключается в том, что класс CString не обеспечивает прямое преобразование приведения типов по дизайну, и то, что вы делаете, является своего рода читерством.

Более длинный ответ следующий:

Причина, по которой вы можете преобразовать CString в LPCTSTR, заключается в том, что CString предоставляет эту возможность, переопределяя operator=. По дизайну он обеспечивает преобразование только в указатель LPCTSTR, поэтому строковое значение не может быть изменено с помощью этого указателя.

Другими словами, он просто не предоставляет перегрузки operator= для преобразования CString в LPSTR по той же причине, что и выше. Они не хотят позволять изменять строковое значение таким образом.

По сути, фокус состоит в том, чтобы использовать оператор CString, предоставленный и получить следующее:

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

Теперь LPTSTR можно преобразовать в LPSTR :)

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

Правильный способ получить LPTSTR из CString - это (полный пример):

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

Опять же, потому что GetBuffer () возвращает LPTSTR по этой причине, теперь вы можете изменить :)

person zar    schedule 15.12.2020