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сработает ... но однажды, когда вы меньше всего этого ожидаете ...


1
Вам следует избегать приведения стиля C и использовать xxx_cast<>()вместо него.
— harper

@harper Вы совершенно правы, но я цитировал OP, это код, о котором он спрашивал. Если бы я написал код сам, он бы наверняка использовал xxx_cast<>вместо смешивания двух разных стилей приведения на основе скобок!
— AAT
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.