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.