LPCSTR, LPCTSTR і LPTSTR


109

Яка різниця між LPCSTR, LPCTSTRі LPTSTR?

Чому нам потрібно це зробити, щоб перетворити рядок у змінну LV/ _ITEMструктура pszText:

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

2
Не могли б ви сказати, що саме тип "рядок"? (наприклад, CString)
Джон Сіблі

Відповіді:


122

Щоб відповісти на першу частину вашого питання:

LPCSTRє вказівником на рядок const (LP означає Long Pointer )

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

LPTSTRє вказівником на TCHARрядок (не-const)

На практиці, коли ми говорили про це в минулому, ми залишили фразу "вказівник на" для простоти, але, як зазначає легкість перегонів на орбіті, вони всі покажчики.

Це чудова стаття з кодовим проектом, що описує рядки C ++ (див. Схему порівняння різних типів 2/3 вниз)


18
Все неправильно. Жодна з цих речей не є струнами. Всі вони - покажчики. -1
гонки легкості по орбіті

8
@LightnessRacesinOrbit Ви технічно правильні, хоча, на моєму досвіді, звичайна практика залишати опис "покажчика на ...." для стислості при посиланні на типи рядків у C ++
Джон Сіблі

2
@JohnSbly: В С, так. У C ++ це абсолютно не повинно бути !!
Гонки легкості по орбіті

4
Зауважте, що ця стаття з кодовим проектом була написана 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, в цьому випадку я думаю, що вони означають, що символьний рядок є const, а не покажчик const.

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: псевдонім char- тип даних Windows
  • LPSTR: Завершується нулем рядок CHAR ( L Ong P ointer)
  • LPCSTR: Константа завершується нулем рядок CHAR ( L Ong P ointer)

16-розрядні UnicodeStrings

  • wchar_t: 16-бітний символ - базовий тип даних C / C ++
  • WCHAR: псевдонім 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
Ганьба ця відповідь ніколи не зробить її вгорі, оскільки вона така нова. Це дійсно щось ТАК потрібно виправити. Це найкраща відповідь на сьогоднішній день.
Ден Бешард

Це дійсно мені дуже допомагає, коли я роблю проект Unicode на роботі. Дякую!
Yoon5oo

Гарна відповідь. Я думаю, що варто додати, що версія unicode використовує UTF16, тому кожен 16-бітний фрагмент - це не символ, а код-одиниця. Назви історичні (коли Unicode === UCS2).
Маргарет Блум

5

Додавання відповіді Джона і Тіма.

Якщо ви не кодуєте Win98, у вашій програмі є лише два типи рядків 6+

  • LPWSTR
  • LPCWSTR

Решта призначені для підтримки платформ ANSI або подвійних компіляцій. Вони сьогодні не такі актуальні, як раніше.


2
@BlueRaja, я в основному мав на увазі рядки на основі С у своїй відповіді. Але для C ++ я б цього не уникав, std::stringтому що це все-таки рядок на основі ASCII і віддаю перевагу std::wstringзамість цього.
JaredPar

1
Ви повинні використовувати LPTSTR та LPCTSTR, якщо ви безпосередньо не викликаєте версії функцій ASCII (* A) або широкоформатний (* W). Вони є псевдонімами будь-якої ширини символів, яку ви вказали під час компіляції.
osvein

... І тепер, коли Microsoft працює над тим, щоб зробити *Aверсії WinAPI сумісними з кодовою сторінкою UTF-8, вони раптом набагато актуальніші. ; P
Час Джастіна -

4

Щоб відповісти на другу частину вашого питання, вам потрібно зробити такі речі

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

оскільки LVITEMструктура MS має LPTSTR, тобто змінний вказівник T-рядка, а не an LPCTSTR. Що ти робиш, так і є

1) перетворити string(a CStringat здогадка) в LPCTSTR(що на практиці означає отримати адресу свого буфера символів як покажчик лише для читання)

2) перетворити цей покажчик лише для читання у вказівник, що записується, відкинувши його const-ness.

Це залежить від того, що dispinfoвикористовується для того, чи існує ймовірність, що ваш ListViewдзвінок закінчиться спробою написати через це pszText. Якщо це так, це потенційно дуже погано: адже вам дали вказівник лише для читання, а потім вирішили ставитися до нього як до запису: можливо, є причина, щоб він був лише для читання!

Якщо це CStringробота, з якою ви працюєте, у вас є можливість використовувати string.GetBuffer()- це свідомо дає вам можливість запису LPTSTR. Тоді вам слід пам'ятати, щоб зателефонувати, ReleaseBuffer()якщо рядок все-таки змінився. Або ви можете виділити локальний тимчасовий буфер і скопіювати туди рядок.

У 99% випадків це буде непотрібним і поводження з LPCTSTRним LPTSTRбуде спрацьовувати ... але одного дня, коли ви найменше цього очікуєте ...


1
Ви повинні уникати акторів стилю C і використовувати їх xxx_cast<>()замість.
харпер

@harper Ви абсолютно праві - але я цитував ОП, це код, про який він питав. Якби я написав сам код, він, звичайно, використовував би, xxx_cast<>а не змішування двох різних стилів кастингу на основі дужок!
ААТ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.