LPCSTR, LPCTSTR e LPTSTR

109

Qual é a diferença entre LPCSTR, LPCTSTRe LPTSTR?

Por que precisamos fazer isso para converter uma string em uma variável LV/ _ITEMstructure pszText:

LV_DISPINFO dispinfo;  
dispinfo.item.pszText = LPTSTR((LPCTSTR)string);
nothingMaster
fonte
2
Você poderia dizer exatamente que tipo de "string" é? (por exemplo, CString)
John Sibly

Respostas:

122

Para responder à primeira parte da sua pergunta:

LPCSTRé um ponteiro para uma string const (LP significa Ponteiro Longo )

LPCTSTRé um ponteiro para uma const TCHARstring ( TCHARsendo um caractere largo ou caractere dependendo se UNICODE está definido em seu projeto)

LPTSTRé um ponteiro para uma TCHARstring (não const)

Na prática, quando falamos sobre isso no passado, deixamos de fora a frase "ponteiro para" para simplificar, mas, como mencionado pelas corridas de leveza em órbita, todos são ponteiros.

Este é um ótimo artigo de projeto de código que descreve strings C ++ (consulte 2/3 abaixo para ver um gráfico comparando os diferentes tipos)

John Sibly
fonte
18
Tudo errado. Nenhuma dessas coisas são cordas. Eles são todos indicadores. -1
Corridas de leveza em órbita
8
@LightnessRacesinOrbit Você está tecnicamente correto - embora na minha experiência seja uma prática comum omitir a descrição de "ponteiro para um ...." para resumir ao se referir a tipos de string em C ++
John Sibly
2
@JohnSibly: Em C, sim. Em C ++, não deveria ser !!
Lightness Races in Orbit
4
Observe que esse artigo codeproject foi escrito 15 anos atrás e, a menos que seja atualizado, contém suposições enganosas sobre os caracteres Unicode sempre terem 2 bytes. Isso está totalmente errado. Mesmo UTF16 tem comprimento variável ... é muito melhor dizer que caracteres largos são codificados em UCS-2 e que "Unicode" neste contexto se refere a UCS-2.
u8it
1
Hmm ... neste caso, @LightnessRacesinOrbit, eu adicionaria um adendo de que não há problema em deixar de fora o "ponteiro para um ..." ao referir-se a strings C em C ++, se e somente se referindo-se especificamente a literais de string (decadentes), ou ao fazer interface / trabalhar com código escrito em C, depende de tipos C em vez de tipos C ++ e / ou tem ligação C via extern "C". Além disso, sim, ele definitivamente deve precisar do bit "ponteiro" ou de uma descrição específica como uma string C.
Hora de Justin - Reintegrar Monica
87

Rapido e sujo:

LP== L ong P ointer. Basta pensar em ponteiro ou char *

C= C onst, neste caso, acho que eles significam que a string de caracteres é uma const, e não o ponteiro sendo const.

STRé string

o Té para uma grande personagem ou char (TCHAR), dependendo das opções de compilação.

Tim
fonte
16
T não é para caracteres largos, é para tipos de caracteres variados. W é para largo (como em WCHAR). Se UNICODE for definido, TCHAR == WCHAR, caso contrário, TCHAR == CHAR. Portanto, se UNICODE não for definido, LPCTSTR == LPCSTR.
jalf
10
é por isso que escrevi "dependendo das opções de compilação"
Tim
14
Eu realmente amo esse tipo de explicação :). Muito obrigado
Dzung Nguyen
@jalf, então o que T significa?
Pacerier de
3
T significa T ext
Ian Boyd
36

AnsiStrings de 8 bits

  • char: Caractere de 8 bits - tipo de dados C / C ++ subjacente
  • CHAR: alias de char- tipo de dados do Windows
  • LPSTR: string terminada em nulo de CHAR ( L ong P ointer)
  • LPCSTR: string constante terminada em nulo de CHAR ( L ong P ointer)

UnicodeStrings de 16 bits

  • wchar_t: Caractere de 16 bits - tipo de dados C / C ++ subjacente
  • WCHAR: alias de wchar_t- tipo de dados do Windows
  • LPWSTR: string terminada em nulo de WCHAR ( L ong P ointer)
  • LPCWSTR: string constante terminada em nulo de WCHAR ( L ong P ointer)

dependendo de UNICODEdefinir

  • TCHAR: alias de WCHARse UNICODE for definido; de outra formaCHAR
  • LPTSTR: string terminada em nulo de TCHAR ( L ong P ointer)
  • LPCTSTR: string constante terminada em nulo de TCHAR ( L ong P ointer)

assim

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

Leitura de bônus

TCHARCaractere de texto ( arquivo.is )

Ian Boyd
fonte
4
É uma pena que essa resposta nunca chegue ao topo porque é tão novo ... isso é realmente algo que MUITO precisa consertar. Esta é a melhor resposta de longe.
Dan Bechard,
Isso realmente me ajuda muito enquanto estou fazendo um projeto Unicode no trabalho. Obrigado!
Yoon5oo
Boa resposta. Acho que vale a pena acrescentar que a versão Unicode usa UTF16, então cada pedaço de 16 bits não é um caractere, mas uma unidade de código. Os nomes são históricos (quando Unicode === UCS2).
Margaret Bloom
5

Somando-se à resposta de John e Tim.

A menos que você esteja codificando para Win98, existem apenas dois dos mais de 6 tipos de string que você deve usar em seu aplicativo

  • LPWSTR
  • LPCWSTR

O restante destina-se a suportar plataformas ANSI ou compilações duplas. Esses não são tão relevantes hoje como costumavam ser.

JaredPar
fonte
2
@BlueRaja, eu estava me referindo principalmente a strings baseadas em C em minha resposta. Mas, para C ++, eu evitaria std::stringporque ainda é uma string baseada em ASCII e prefiro std::wstring.
JaredPar
1
Você deve usar LPTSTR e LPCTSTR, a menos que esteja chamando as versões ASCII (* A) ou widechar (* W) das funções diretamente. Eles são apelidos de qualquer largura de caractere que você especificar ao compilar.
osvein
... E agora que a Microsoft está trabalhando para tornar as *Aversões do WinAPI compatíveis com a página de código UTF-8, de repente elas são muito mais relevantes. ; P
Hora de Justin - Reintegrar Monica
4

Para responder à segunda parte da sua pergunta, você precisa fazer coisas como

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

porque a LVITEMestrutura de MS tem um LPTSTR, ou seja, um ponteiro mutável de string T, não um LPCTSTR. O que você está fazendo é

1) converter string(a CStringem um palpite) em um LPCTSTR(o que na prática significa obter o endereço de seu buffer de caracteres como um ponteiro somente leitura)

2) converter aquele ponteiro somente leitura em um ponteiro gravável descartando sua const-ness.

Depende do que dispinfoé usado se há ou não uma chance de que sua ListViewchamada acabe tentando escrever através disso pszText. Se isso acontecer, isso é potencialmente muito ruim: afinal, você recebeu um ponteiro somente leitura e decidiu tratá-lo como gravável: talvez haja um motivo pelo qual ele era somente leitura!

Se for um com o qual CStringvocê está trabalhando, você tem a opção de usar string.GetBuffer()- isso deliberadamente dá a você um gravável LPTSTR. Em seguida, você deve se lembrar de chamar ReleaseBuffer()se a string for alterada. Ou você pode alocar um buffer temporário local e copiar a string para lá.

99% das vezes isso será desnecessário e tratá-los LPCTSTRcomo um LPTSTRfuncionará ... mas um dia, quando você menos esperar ...

AAT
fonte
1
Você deve evitar elenco de estilo C e usar em seu xxx_cast<>()lugar.
Harper de
@harper Você está certo - mas eu estava citando o OP, esse é o código que ele estava perguntando. Se eu mesmo tivesse escrito o código, certamente teria usado em xxx_cast<>vez de misturar dois estilos de fundição baseados em colchetes diferentes!
AAT