LPCSTR, LPCTSTR und LPTSTR

108

Was ist der Unterschied zwischen LPCSTR, LPCTSTRund LPTSTR?

Warum müssen wir dies tun, um einen String in eine LV/ _ITEMStrukturvariable zu konvertieren pszText:

LV_DISPINFO dispinfo;  
dispinfo.item.pszText = LPTSTR((LPCTSTR)string);
NothingMaster
quelle
2
Können Sie genau sagen, welcher Typ "Zeichenfolge" ist? (zB CString)
John Sibly

Antworten:

122

So beantworten Sie den ersten Teil Ihrer Frage:

LPCSTRist ein Zeiger auf eine konstante Zeichenfolge (LP bedeutet Long Pointer )

LPCTSTRist ein Zeiger auf eine const TCHARZeichenfolge ( TCHARentweder ein breites Zeichen oder ein Zeichen, je nachdem, ob UNICODE in Ihrem Projekt definiert ist).

LPTSTRist ein Zeiger auf eine (nicht konstante) TCHARZeichenfolge

In der Praxis haben wir, wenn wir in der Vergangenheit darüber gesprochen haben, der Einfachheit halber den "Zeiger auf eine" Phrase weggelassen, aber wie von Leichtigkeitsrennen im Orbit erwähnt, sind sie alle Zeiger.

Dies ist ein großartiger Codeprojekt-Artikel , der C ++ - Zeichenfolgen beschreibt (siehe 2/3 unten für ein Diagramm, in dem die verschiedenen Typen verglichen werden).

John Sibly
quelle
17
Alles falsch. Keines dieser Dinge ist eine Zeichenfolge. Sie sind alle Zeiger. -1
Leichtigkeitsrennen im Orbit
8
@LightnessRacesinOrbit Sie sind technisch korrekt - obwohl es meiner Erfahrung nach üblich ist, die Beschreibung "Zeiger auf ein ...." der Kürze halber wegzulassen, wenn Sie sich auf Zeichenfolgentypen in C ++ beziehen
John Sibly
2
@ JohnSibly: In C ja. In C ++ sollte es absolut nicht sein !!
Leichtigkeitsrennen im Orbit
4
Beachten Sie, dass dieser Codeprojektartikel vor 15 Jahren geschrieben wurde und, sofern er nicht aktualisiert wird, irreführende Annahmen darüber enthält, dass Unicode-Zeichen immer 2 Byte groß sind. Das ist völlig falsch. Sogar UTF16 hat eine variable Länge ... es ist viel besser zu sagen, dass breite Zeichen UCS-2-codiert sind und dass "Unicode" in diesem Zusammenhang auf UCS-2 verweist.
U8it
1
Hmm ... in diesem Fall, @LightnessRacesinOrbit, würde ich einen Nachtrag hinzufügen, dass es in Ordnung ist, den "Zeiger auf ein ..." wegzulassen, wenn auf C-Strings in C ++ verwiesen wird, wenn und nur wenn speziell darauf verwiesen wird (verfallene) String-Literale oder bei der Schnittstelle / Arbeit mit Code, der entweder in C geschrieben ist, werden C-Typen anstelle von C ++ - Typen verwendet und / oder C-Verknüpfungen über extern "C". Abgesehen davon sollte es definitiv entweder das "Zeiger" -Bit oder eine spezifische Beschreibung als C-Zeichenfolge benötigen.
Justin Time - Stellen Sie Monica
87

Schnell und dreckig:

LP== L ong P ointer. Denken Sie nur an Zeiger oder Zeichen *

C= C onst, in diesem Fall denke ich, dass die Zeichenfolge eine Konstante ist, nicht der Zeiger eine Konstante.

STRist Zeichenfolge

das Tist für ein breites Zeichen oder Zeichen (TCHAR) , je nach Kompilierungsoptionen.

Tim
quelle
16
T ist nicht für breite Zeichen, sondern für unterschiedliche Zeichentypen. W ist für breit (wie in WCHAR). Wenn UNICODE definiert ist, ist TCHAR == WCHAR, andernfalls TCHAR == CHAR. Wenn also UNICODE nicht definiert ist, ist LPCTSTR == LPCSTR.
Jalf
10
Deshalb habe ich "abhängig von den Kompilierungsoptionen" geschrieben
Tim
14
Ich liebe diese Art des Erklärens wirklich :). Vielen Dank
Dzung Nguyen
@jalf, wofür steht T?
Pacerier
3
T bedeutet T ext
Ian Boyd
36

8-Bit-AnsiStrings

  • char: 8-Bit-Zeichen - zugrunde liegender C / C ++ - Datentyp
  • CHAR: Alias ​​von char- Windows-Datentyp
  • LPSTR: nullterminierte Zeichenfolge von CHAR ( L ong P ointer)
  • LPCSTR: Konstante nullterminierte Zeichenfolge von CHAR ( L ong P ointer)

16-Bit-UnicodeStrings

  • wchar_t: 16-Bit-Zeichen - zugrunde liegender C / C ++ - Datentyp
  • WCHAR: Alias ​​von wchar_t- Windows-Datentyp
  • LPWSTR: nullterminierte Zeichenfolge von WCHAR ( L ong P ointer)
  • LPCWSTR: Konstante nullterminierte Zeichenfolge von WCHAR ( L ong P ointer)

je nach UNICODEdefinieren

  • TCHAR: Alias ​​von WCHARwenn UNICODE definiert ist; AndernfallsCHAR
  • LPTSTR: nullterminierte Zeichenfolge von TCHAR ( L ong P ointer)
  • LPCTSTR: Konstante nullterminierte Zeichenfolge von TCHAR ( L ong P ointer)

So

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

Bonuslesung

TCHARText Char ( archive.is )

Ian Boyd
quelle
4
Schade, dass diese Antwort niemals an die Spitze kommt, weil sie so neu ist. Das muss SO wirklich beheben. Dies ist bei weitem die beste Antwort.
Dan Bechard
Das hilft mir sehr, während ich ein Unicode-Projekt bei der Arbeit mache. Vielen Dank!
Yoon5oo
Gute Antwort. Ich denke, es lohnt sich hinzuzufügen, dass die Unicode-Version UTF16 verwendet, sodass jeder 16-Bit-Block kein Zeichen, sondern eine Codeeinheit ist. Die Namen sind historisch (wenn Unicode === UCS2).
Margaret Bloom
5

Hinzufügen zu Johns und Tims Antwort.

Sofern Sie nicht für Win98 codieren, gibt es nur zwei der mehr als 6 Zeichenfolgentypen, die Sie in Ihrer Anwendung verwenden sollten

  • LPWSTR
  • LPCWSTR

Der Rest soll ANSI-Plattformen oder Dual-Compilations unterstützen. Diese sind heute nicht mehr so ​​relevant wie früher.

JaredPar
quelle
2
@BlueRaja, ich habe mich in meiner Antwort hauptsächlich auf C-basierte Zeichenfolgen bezogen. Aber für C ++ würde ich vermeiden, std::stringweil es immer noch eine ASCII-basierte Zeichenfolge ist und std::wstringstattdessen bevorzugen .
JaredPar
1
Sie sollten LPTSTR und LPCTSTR verwenden, es sei denn, Sie rufen die ASCII- (* A) oder Widechar- (* W) Versionen von Funktionen direkt auf. Sie sind Aliase mit der Zeichenbreite, die Sie beim Kompilieren angeben.
Osvein
... Und jetzt, da Microsoft daran arbeitet, die *AVersionen von WinAPI mit der UTF-8-Codepage kompatibel zu machen, sind sie plötzlich viel relevanter. ; P
Justin Time - Wiedereinsetzung Monica
4

Um den zweiten Teil Ihrer Frage zu beantworten, müssen Sie Dinge wie tun

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

weil die LVITEMStruktur von MS einen LPTSTR, dh einen veränderlichen T-String-Zeiger hat, keinen LPCTSTR. Was Sie tun, ist

1) konvertiere string(a CStringa rate) in a LPCTSTR(was in der Praxis bedeutet, die Adresse seines Zeichenpuffers als schreibgeschützten Zeiger zu erhalten)

2) Konvertieren Sie diesen schreibgeschützten Zeiger in einen beschreibbaren Zeiger, indem Sie seine const-ness wegwerfen.

Es hängt davon ab, wofür verwendet dispinfowird, ob die Möglichkeit besteht, dass Ihr ListViewAnruf versucht , dies durchzuschreiben pszText. Wenn dies der Fall ist, ist dies möglicherweise eine sehr schlechte Sache: Schließlich haben Sie einen schreibgeschützten Zeiger erhalten und dann beschlossen, ihn als beschreibbar zu behandeln: Vielleicht gibt es einen Grund, warum er schreibgeschützt war!

Wenn es ein CStringist, mit dem Sie arbeiten, haben Sie die Möglichkeit zu verwenden string.GetBuffer()- das gibt Ihnen absichtlich eine beschreibbare LPTSTR. Sie müssen dann daran denken, aufzurufen, ReleaseBuffer()wenn die Zeichenfolge geändert wird. Oder Sie können einen lokalen temporären Puffer zuweisen und die Zeichenfolge dort kopieren.

99% der Zeit wird dies unnötig sein und die Behandlung LPCTSTRals ein LPTSTRWille funktionieren ... aber eines Tages, wenn Sie es am wenigsten erwarten ...

AAT
quelle
1
Sie sollten Cast im C-Stil vermeiden und xxx_cast<>()stattdessen verwenden.
Harper
@harper Du hast ganz recht - aber ich habe das OP zitiert, das ist der Code, nach dem er gefragt hat. Wenn ich den Code selbst geschrieben hätte, hätte er sicherlich xxx_cast<>zwei verschiedene klammerbasierte Casting-Stile verwendet, anstatt sie zu mischen!
AAT