LPCSTR, LPCTSTR et LPTSTR

109

Quelle est la différence entre LPCSTR, LPCTSTRet LPTSTR?

Pourquoi avons-nous besoin de faire cela pour convertir une chaîne en une variable LV/ _ITEMstructure pszText:

LV_DISPINFO dispinfo;  
dispinfo.item.pszText = LPTSTR((LPCTSTR)string);
rienMaster
la source
2
Pouvez-vous dire exactement quel est le type de "chaîne"? (par exemple CString)
John Sibly

Réponses:

122

Pour répondre à la première partie de votre question:

LPCSTRest un pointeur vers une chaîne const (LP signifie Long Pointer )

LPCTSTRest un pointeur vers une const TCHARchaîne, ( TCHARétant un caractère large ou un caractère selon que UNICODE est défini dans votre projet)

LPTSTRest un pointeur vers une TCHARchaîne (non-const)

En pratique, lorsque nous en parlons dans le passé, nous avons laissé de côté l'expression «pointeur vers une» pour simplifier, mais comme mentionné par les courses de légèreté en orbite, ce sont toutes des pointeurs.

Ceci est un excellent article de projet de code décrivant les chaînes C ++ (voir 2/3 en bas pour un graphique comparant les différents types)

John Sibly
la source
18
Tout faux. Aucune de ces choses n'est des chaînes. Ce sont tous des pointeurs. -1
Courses de légèreté en orbite
8
@LightnessRacesinOrbit Vous avez techniquement raison - même si, d'après mon expérience, il est courant de laisser de côté la description «pointeur vers un ....» par souci de brièveté lorsque vous vous référez aux types de chaînes en C ++
John Sibly
2
@JohnSably: En C, oui. En C ++, cela ne devrait absolument pas être !!
Courses de légèreté en orbite le
4
Notez que cet article de projet de code a été écrit il y a 15 ans et, à moins qu'il ne soit mis à jour, contient des hypothèses trompeuses sur le fait que les caractères Unicode sont toujours de 2 octets. C'est complètement faux. Même UTF16 est de longueur variable ... il vaut mieux dire que les caractères larges sont codés UCS-2, et que "Unicode" dans ce contexte se réfère à UCS-2.
u8it
1
Hmm ... dans ce cas, @LightnessRacesinOrbit, j'ajouterais un addendum indiquant qu'il est normal de laisser de côté le "pointeur vers un ..." en se référant aux chaînes C en C ++, si-et-seulement-si se référant spécifiquement à littéraux de chaîne (décomposés), ou lors de l'interfaçage / travail avec du code qui est soit écrit en C, repose sur des types C au lieu de types C ++, et / ou a une liaison C via extern "C". En dehors de cela, oui, il devrait certainement avoir besoin du bit "pointeur" ou d'une description spécifique sous forme de chaîne C.
Justin Time - Réintègre Monica le
87

Rapide et sale:

LP== L ong P ointer. Pensez juste au pointeur ou au caractère *

C= C onst, dans ce cas, je pense qu'ils signifient que la chaîne de caractères est un const, pas le pointeur étant const.

STRest une chaîne

le Test pour un caractère large ou char (TCHAR) selon les options de compilation.

Tim
la source
16
T n'est pas pour un caractère large, mais pour un type de caractère variable. W est pour large (comme dans WCHAR). Si UNICODE est défini, TCHAR == WCHAR, sinon TCHAR == CHAR. Donc, si UNICODE n'est pas défini, LPCTSTR == LPCSTR.
jalf
10
c'est pourquoi j'ai écrit "selon les options de compilation"
Tim
14
J'aime vraiment ce type d'explication :). Merci beaucoup
Dzung Nguyen
@jalf, alors que signifie T?
Pacerier
3
T signifie T ext
Ian Boyd
36

AnsiStrings 8 bits

  • char: Caractère 8 bits - type de données C / C ++ sous-jacent
  • CHAR: alias de char- type de données Windows
  • LPSTR: chaîne terminée par un zéro de CHAR ( L ong P ointer)
  • LPCSTR: chaîne constante terminée par un zéro de CHAR ( L ong P ointer)

UnicodeStrings 16 bits

  • wchar_t: Caractère 16 bits - type de données C / C ++ sous-jacent
  • WCHAR: alias de wchar_t- type de données Windows
  • LPWSTR: chaîne terminée par un zéro de WCHAR ( L ong P ointer)
  • LPCWSTR: chaîne constante terminée par un zéro de WCHAR ( L ong P ointer)

selon UNICODEdéfinir

  • TCHAR: alias de WCHARsi UNICODE est défini; autrementCHAR
  • LPTSTR: chaîne terminée par un zéro de TCHAR ( L ong P ointer)
  • LPCTSTR: chaîne constante terminée par un zéro de TCHAR ( L ong P ointer)

Alors

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

Lecture bonus

TCHARCaractère texte ( archive.is )

Ian Boyd
la source
4
Dommage que cette réponse ne parvienne jamais au sommet parce que c'est tellement nouveau ... c'est vraiment quelque chose que SO doit corriger. C'est de loin la meilleure réponse.
Dan Bechard
Cela m'aide vraiment beaucoup pendant que je fais un projet Unicode au travail. Merci!
Yoon5oo
Bonne réponse. Je pense qu'il vaut la peine d'ajouter que la version unicode utilise UTF16, de sorte que chaque morceau de 16 bits n'est pas un caractère mais une unité de code. Les noms sont historiques (quand Unicode === UCS2).
Margaret Bloom le
5

Ajout à la réponse de John et Tim.

Sauf si vous codez pour Win98, il n'y a que deux des 6 types de chaînes ou plus que vous devriez utiliser dans votre application

  • LPWSTR
  • LPCWSTR

Le reste est destiné à prendre en charge les plates-formes ANSI ou les doubles compilations. Celles-ci ne sont plus aussi pertinentes aujourd'hui qu'elles l'étaient auparavant.

JaredPar
la source
2
@BlueRaja, je faisais principalement référence aux chaînes basées sur C dans ma réponse. Mais pour C ++, j'éviterais std::stringcar il s'agit toujours d'une chaîne basée sur ASCII et je préfère à la std::wstringplace.
JaredPar
1
Vous devez utiliser LPTSTR et LPCTSTR sauf si vous appelez directement les versions ASCII (* A) ou widechar (* W) des fonctions. Ce sont des alias de la largeur de caractère que vous spécifiez lors de la compilation.
osvein
... Et maintenant que Microsoft travaille à rendre les *Aversions de WinAPI compatibles avec la page de codes UTF-8, elles sont soudainement beaucoup plus pertinentes. ; P
Justin Time - Réintègre Monica le
4

Pour répondre à la deuxième partie de votre question, vous devez faire des choses comme

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

parce que la LVITEMstructure de MS a un LPTSTR, c'est-à-dire un pointeur de chaîne T mutable , pas un LPCTSTR. Ce que tu fais c'est

1) convertir string(a CStringau hasard) en an LPCTSTR(ce qui signifie en pratique obtenir l'adresse de son tampon de caractères comme un pointeur en lecture seule)

2) convertir ce pointeur en lecture seule en un pointeur inscriptible en rejetant son caractère const-ness.

Cela dépend de ce qui dispinfoest utilisé, qu'il y ait ou non une chance que votre ListViewappel finisse par essayer d' écrire à travers cela pszText. Si c'est le cas, c'est une très mauvaise chose: après tout, vous avez reçu un pointeur en lecture seule, puis vous avez décidé de le traiter comme inscriptible: il y a peut-être une raison pour laquelle il était en lecture seule!

Si c'est un CStringavec string.GetBuffer()lequel vous travaillez, vous avez la possibilité d'utiliser - cela vous donne délibérément un fichier LPTSTR. Vous devez ensuite vous rappeler d'appeler ReleaseBuffer()si la chaîne est modifiée. Ou vous pouvez allouer un tampon temporaire local et y copier la chaîne.

99% du temps, ce sera inutile et le traiter LPCTSTRcomme une LPTSTRvolonté fonctionnera ... mais un jour, quand vous vous y attendez le moins ...

AAT
la source
1
Vous devez éviter le cast de style C et l'utiliser à la xxx_cast<>()place.
harper
@harper Vous avez tout à fait raison - mais je citais l'OP, c'est le code dont il parlait. Si j'avais écrit le code moi-même, il aurait certainement utilisé xxx_cast<>plutôt que de mélanger deux styles de casting différents basés sur les crochets!
AAT