LPCSTR, LPCTSTR y LPTSTR

109

Lo que la diferencia entre LPCSTR, LPCTSTRy LPTSTR?

¿Por qué necesitamos hacer esto para convertir una cadena en una variable de estructura LV/ ? _ITEMpszText

LV_DISPINFO dispinfo;  
dispinfo.item.pszText = LPTSTR((LPCTSTR)string);
nada maestro
fuente
2
¿Podría decir exactamente qué tipo de "cadena" es? (por ejemplo, CString)
John Sibly

Respuestas:

122

Para responder a la primera parte de su pregunta:

LPCSTRes un puntero a una cadena constante (LP significa Long Pointer )

LPCTSTRes un puntero a una const TCHARcadena, (puede TCHARser un char ancho o char dependiendo de si UNICODE está definido en su proyecto)

LPTSTRes un puntero a una TCHARcadena (no constante)

En la práctica, cuando hablamos de estos en el pasado, hemos omitido la frase "puntero a una" por simplicidad, pero como se menciona en Lightness-Race-in-Orbit, todos son indicadores.

Este es un gran artículo de proyecto de código que describe cadenas de C ++ (consulte 2/3 en el camino hacia abajo para ver un gráfico que compara los diferentes tipos)

John Sbly
fuente
18
Todo mal. Ninguna de estas cosas son cuerdas. Todos son indicadores. -1
Lightness Races in Orbit
8
@LightnessRacesinOrbit Está técnicamente en lo correcto, aunque en mi experiencia es una práctica común omitir la descripción de "puntero a ..." por brevedad cuando se hace referencia a los tipos de cadena en C ++
John Sibly
2
@JohnSibly: En C, sí. ¡En C ++, absolutamente no debería serlo!
Lightness Races in Orbit
4
Tenga en cuenta que ese artículo del proyecto de código se escribió hace 15 años y, a menos que se actualice, contiene suposiciones engañosas acerca de que los caracteres Unicode siempre tienen 2 bytes. Eso está completamente mal. Incluso UTF16 es de longitud variable ... es mucho mejor decir que los caracteres anchos están codificados en UCS-2 y que "Unicode" en este contexto se refiere a UCS-2.
u8it
1
Hmm ... en este caso, @LightnessRacesinOrbit, agregaría un apéndice en el que está bien omitir el "puntero a un ..." cuando se refiera a cadenas C en C ++, si-y-solo-si se refiere específicamente a (decaído) cadenas literales, o cuando interactúa / trabaja con código que está escrito en C, se basa en tipos C en lugar de tipos C ++ y / o tiene enlace C a través de extern "C". Aparte de eso, sí, definitivamente debería necesitar el bit de "puntero" o una descripción específica como una cadena C.
Justin Time - Reincorpora a Monica el
87

Rápido y sucio:

LP== L ong P ointer. Solo piensa en puntero o char *

C= C onst, en este caso, creo que quieren decir que la cadena de caracteres es una constante, no que el puntero sea constante.

STRes una cuerda

el Tes de un carácter ancho o char (TCHAR) dependiendo de las opciones de compilación.

Tim
fuente
16
T no es para caracteres amplios, es para diferentes tipos de caracteres. W es para ancho (como en WCHAR). Si se define UNICODE, TCHAR == WCHAR, de lo contrario TCHAR == CHAR. Entonces, si UNICODE no está definido, LPCTSTR == LPCSTR.
jalf
10
es por eso que escribí "dependiendo de las opciones de compilación"
Tim
14
Realmente amo este tipo de explicaciones :). Muchas gracias
Dzung Nguyen
@jalf, entonces, ¿qué significa T?
Pacerier
3
T significa T ext
Ian Boyd
36

AnsiStrings de 8 bits

  • char: Carácter de 8 bits - tipo de datos C / C ++ subyacente
  • CHAR: alias de char- tipo de datos de Windows
  • LPSTR: cadena terminada en nulo de CHAR ( L ong P ointer)
  • LPCSTR: cadena constante terminada en nulo de CHAR ( L ong P ointer)

UnicodeStrings de 16 bits

  • wchar_t: Carácter de 16 bits - tipo de datos C / C ++ subyacente
  • WCHAR: alias de wchar_t- tipo de datos de Windows
  • LPWSTR: cadena terminada en nulo de WCHAR ( L ong P ointer)
  • LPCWSTR: cadena constante terminada en nulo de WCHAR ( L ong P ointer)

dependiendo de UNICODEdefinir

  • TCHAR: alias de WCHARsi se define UNICODE; de otra maneraCHAR
  • LPTSTR: cadena terminada en nulo de TCHAR ( L ong P ointer)
  • LPCTSTR: cadena constante terminada en nulo de TCHAR ( L ong P ointer)

Entonces

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

Lectura adicional

TCHARTexto Char ( archive.is )

Ian Boyd
fuente
4
Es una pena que esta respuesta nunca llegue a la cima porque es muy nueva ... eso es realmente algo que SO necesita arreglar. Esta es la mejor respuesta con diferencia.
Dan Bechard
Esto realmente me ayuda mucho mientras hago un proyecto Unicode en el trabajo. ¡Gracias!
Yoon5oo
Buena respuesta. Creo que vale la pena agregar que la versión Unicode usa UTF16, por lo que cada fragmento de 16 bits no es un carácter sino una unidad de código. Los nombres son históricos (cuando Unicode === UCS2).
Margaret Bloom
5

Añadiendo a la respuesta de John y Tim.

A menos que esté codificando para Win98, solo hay dos de los más de 6 tipos de cadenas que debe usar en su aplicación

  • LPWSTR
  • LPCWSTR

El resto está destinado a admitir plataformas ANSI o compilaciones duales. Esos no son tan relevantes hoy como solían ser.

JaredPar
fuente
2
@BlueRaja, me refería principalmente a cadenas basadas en C en mi respuesta. Pero para C ++ lo evitaría std::stringporque sigue siendo una cadena basada en ASCII y prefiero en su std::wstringlugar.
JaredPar
1
Debería utilizar LPTSTR y LPCTSTR a menos que llame directamente a las versiones ASCII (* A) o widechar (* W) de las funciones. Son alias de cualquier ancho de carácter que especifique al compilar.
osvein
... Y ahora que Microsoft está trabajando para hacer que las *Aversiones de WinAPI sean compatibles con la página de códigos UTF-8, de repente son mucho más relevantes. ; P
Justin Time - Reincorporar a Monica
4

Para responder a la segunda parte de su pregunta, debe hacer cosas como

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

porque la LVITEMestructura de MS tiene LPTSTR, es decir, un puntero de cadena T mutable , no un LPCTSTR. Lo que estas haciendo es

1) convertir string(a CStringen una suposición) en unLPCTSTR (que en la práctica significa obtener la dirección de su búfer de caracteres como un puntero de solo lectura)

2) convierta ese puntero de solo lectura en un puntero escribible constdesechando su carácter -ness.

Depende de lo que dispinfose use para saber si existe la posibilidad de que su ListViewllamada termine intentando escribir a través de eso pszText. Si lo hace, esto es algo potencialmente muy malo: después de todo, se le dio un puntero de solo lectura y luego decidió tratarlo como escribible: ¡quizás haya una razón por la que era de solo lectura!

Si está CStringtrabajando con él, tiene la opción de usarlo string.GetBuffer(), que deliberadamente le da una escritura LPTSTR. Entonces tienes que recordar llamarReleaseBuffer() si la cadena se cambia. O puede asignar un búfer temporal local y copiar la cadena allí.

El 99% de las veces esto será innecesario y tratarlo LPCTSTRcomo un LPTSTRtestamento funcionará ... pero un día, cuando menos lo esperes ...

AAT
fuente
1
Debes evitar el yeso estilo C y usar xxx_cast<>()en su lugar.
harper
@harper Tienes razón, pero estaba citando el OP, ese es el código por el que estaba preguntando. Si hubiera escrito el código yo mismo, sin duda habría utilizado en xxx_cast<>lugar de mezclar dos estilos de fundición diferentes basados ​​en corchetes.
AAT