LPCSTR, LPCTSTR и LPTSTR

109

Какая разница между LPCSTR, LPCTSTRи LPTSTR?

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

LV_DISPINFO dispinfo;  
dispinfo.item.pszText = LPTSTR((LPCTSTR)string);
ничего Мастер
источник
2
Не могли бы вы точно сказать, что это за тип «строка»? (например, CString)
Джон Сибли

Ответы:

122

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

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

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

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

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

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

Джон Сибли
источник
18
Все не так. Все это не струны. Все они указатели. -1
Lightness Races на орбите
8
@LightnessRacesinOrbit Вы технически правы - хотя, по моему опыту, это обычная практика для краткости опускать описание «указатель на ....» при обращении к строковым типам в C ++
Джон Силили
2
@JohnSible: В C, да. В C ++ этого быть не должно!
Гонки легкости на орбите
4
Обратите внимание, что эта статья codeproject была написана 15 лет назад и, если она не будет обновлена, содержит вводящие в заблуждение предположения о том, что символы Unicode всегда составляют 2 байта. Это совершенно неверно. Даже UTF16 имеет переменную длину ... гораздо лучше сказать, что широкие символы имеют кодировку UCS-2, и что "Unicode" в этом контексте относится к UCS-2.
u8it
1
Хм ... в этом случае, @LightnessRacesinOrbit, я бы добавил добавление, что можно не указывать «указатель на ...», когда речь идет о C-строках в C ++, если и только если ссылаются конкретно на (распадающиеся) строковые литералы или при взаимодействии / работе с кодом, написанным на C, полагаются на типы C вместо типов C ++ и / или имеют связь с C через extern "C". Кроме того, да, ему определенно нужен либо бит "указатель", либо конкретное описание в виде строки C.
Джастин Тайм - Восстановите Монику
87

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

LP== L Ong P ointer. Просто подумайте, указатель или символ *

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

STRявляется строка

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

Тим
источник
16
T не для широкого символа, это для различного типа символа. W означает широкий (как в WCHAR). Если определен UNICODE, TCHAR == WCHAR, иначе TCHAR == CHAR. Итак, если UNICODE не определен, LPCTSTR == LPCSTR.
jalf
10
вот почему я написал «в зависимости от параметров компиляции»
Тим
14
Мне очень нравятся такие объяснения :). Большое спасибо
Джунг Нгуен
@jalf, Так что же означает T?
Pacerier
36

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

  • char: 8-битный символ - базовый тип данных C / C ++
  • CHAR: alias of char- Тип данных Windows
  • LPSTR: Завершается нулем строка CHAR ( L Ong P ointer)
  • LPCSTR: Константа завершается нулем строка CHAR ( L Ong P ointer)

16-битные UnicodeStrings

  • wchar_t: 16-битный символ - базовый тип данных C / C ++
  • WCHAR: alias of wchar_t- Тип данных Windows
  • LPWSTR: Завершается нулем строка WCHAR ( L Ong P ointer)
  • LPCWSTR: Константа завершается нулем строка WCHAR ( L Ong P ointer)

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

  • TCHAR: псевдоним, WCHARесли определен UNICODE; в противном случаеCHAR
  • LPTSTR: Завершается нулем строка TCHAR ( L Ong P ointer)
  • LPCTSTR: Константа завершается нулем строка TCHAR ( L Ong P ointer)

Так

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

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

TCHARТекстовый символ ( archive.is )

Ян Бойд
источник
4
Жаль, что этот ответ никогда не дойдет до вершины, потому что он такой новый ... это действительно то, что SO нужно исправить. На сегодняшний день это лучший ответ.
Дэн Бечард
Это действительно очень помогает мне, когда я работаю над проектом Unicode. Спасибо!
Yoon5oo
Хороший ответ. Я думаю, стоит добавить, что версия unicode использует UTF16, поэтому каждый 16-битный фрагмент является не символом, а единицей кода. Имена исторические (когда Unicode === UCS2).
Маргарет Блум
5

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

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

  • LPWSTR
  • LPCWSTR

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

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

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

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

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

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

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

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

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

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

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