【问题标题】:LPCSTR, LPCTSTR and LPTSTRLPCSTR、LPCTSTR 和 LPTSTR
【发布时间】:2010-09-24 04:46:54
【问题描述】:

LPCSTRLPCTSTRLPTSTR 有什么区别?

为什么我们需要这样做将字符串转换成LV/_ITEM结构变量pszText

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

【问题讨论】:

  • 你能准确地说出“字符串”是什么类型吗? (例如 CString)

标签: c++ windows visual-c++ mfc


【解决方案1】:

又快又脏:

LP == Long Pointer。想想指针或字符*

C = Const,在这种情况下,我认为它们的意思是字符串是 const,而不是指针是 const。

STR字符串

T 用于宽字符或字符 (TCHAR),具体取决于编译器选项。

阅读奖励

来自What does the letter "T" in LPTSTR stand for?archive

LPTSTR 中的字母“T”代表什么?

2006 年 10 月 17 日

LPTSTR 中的“T”来自 TCHAR 中的“T”。我不确定,但它似乎很可能代表“文本”。相比之下,WCHAR 中的“W”可能来自 C 语言标准,它代表“宽”。

【讨论】:

  • T 不用于宽字符,它用于不同的字符类型。 W 代表宽(如在 WCHAR 中)。如果定义了 UNICODE,则 TCHAR == WCHAR,否则 TCHAR == CHAR。所以如果没有定义UNICODE,LPCTSTR == LPCSTR。
  • 这就是我写“取决于编译选项”的原因
  • 我真的很喜欢这种解释方式:)。非常感谢
  • @jalf,那么 T 代表什么?
【解决方案2】:

8 位 AnsiStrings

  • char: 8 位字符(底层 C/C++ 数据类型)
  • CHARchar 的别名(Windows 数据类型)
  • LPSTRCHAR 的以 null 结尾的字符串 (Long Pointer)
  • LPCSTRCHAR 的常量以 null 结尾的字符串 (Long Pointer Constant)

16 位 Unicode 字符串

  • wchar_t: 16 位字符(底层 C/C++ 数据类型)
  • WCHARwchar_t 的别名(Windows 数据类型)
  • LPWSTRWCHAR 的以 null 结尾的字符串 (Long Pointer)
  • LPCWSTRWCHAR 的常量以 null 结尾的字符串 (Long Pointer Constant)

取决于UNICODE 定义

  • TCHAR:如果定义了 UNICODE,则为 WCHAR 的别名;否则CHAR
  • LPTSTRTCHAR 的以 null 结尾的字符串 (Long Pointer)
  • LPCTSTRTCHAR 的常量以 null 结尾的字符串 (Long Pointer Constant)

所以:

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

阅读奖励

TCHARText Char (archive.is)


Why is the default 8-bit codepage called "ANSI"?

来自Unicode and Windows XP
凯茜·威辛克
项目经理,Windows 全球化
微软公司
2002 年 5 月

尽管 Windows NT 3.1 支持底层 Unicode,但代码页支持 对于系统中包含的许多更高级别的应用程序和组件仍然是必需的,解释了 Win32 API 的“A”[ANSI] 版本而不是“W”[“wide”或 Unicode] 版本的普遍使用. (用于表示 Windows 代码页的术语“ANSI”是一个历史参考,但如今在 Windows 社区中继续存在的一个误称。这源于 Windows 代码页 1252 最初基于ANSI 草案,后来成为 ISO 标准 8859-1。但是,在向 ISO 标准中为控制代码保留的范围添加代码点时,Windows 代码页 1252 和最初基于 ISO 8859-x 系列的后续 Windows 代码页偏离了直到今天,Microsoft 内部和外部的开发社区将 8859-1 代码页与 Windows 1252 混淆并看到用于表示 Windows 的“ANSI”或“A”的情况并不少见代码页支持。)

【讨论】:

  • 遗憾的是,这个答案永远不会登上榜首,因为它太新了……这确实是需要解决的问题。这是迄今为止最好的答案。
  • 当我在工作中做 Unicode 项目时,这对我帮助很大。谢谢!
  • 不错的答案。我认为值得补充的是,unicode 版本使用 UTF16,因此每个 16 位块不是字符而是代码单元。这些名称是历史名称(当 Unicode === UCS2 时)。
【解决方案3】:

对问题第二部分的简短回答是,CString 类没有通过设计提供直接类型转换,您所做的就是一种作弊。

更长的答案如下:

您可以将CString 键入到LPCTSTR 的原因是因为CString 通过覆盖operator= 提供了此功能。按照设计,它只提供到 LPCTSTR 指针的转换,因此不能用这个指针修改字符串值。

换句话说,出于与上述相同的原因,它根本不提供重载operator=CString 转换为LPSTR。他们不想允许以这种方式更改字符串值。

所以本质上,诀窍是使用 CString 提供的运算符并得到这个:

LPTSTR lptstr = (LPCTSTR) string; // CString provide this operator overload

现在 LPTSTR 可以进一步类型转换为 LPSTR :)

dispinfo.item.pszText = LPTSTR( lpfzfd); // accomplish the cheat :P

从“CString”获取LPTSTR的正确方法是这样的(完整示例):

CString str = _T("Hello");
LPTSTR lpstr = str.GetBuffer(str.GetAllocLength());
str.ReleaseBuffer(); // you must call this function if you change the string above with the pointer

同样是因为 GetBuffer() 返回 LPTSTR,因此现在您可以修改 :)

【讨论】:

    【解决方案4】:

    回答你问题的第一部分:

    LPCSTR 是一个指向 const 字符串的指针(LP 表示 Long Pointer

    LPCTSTR 是一个指向 const TCHAR 字符串的指针,(TCHAR 是宽字符还是字符,取决于您的项目中是否定义了 UNICODE)

    LPTSTR 是指向(非常量)TCHAR 字符串的指针

    实际上,在过去谈论这些时,为了简单起见,我们省略了“指向一个”短语,但正如在轨道上的轻量级所提到的,它们都是指针。

    这是一个很棒的 codeproject article 描述 C++ 字符串(请参阅下面 2/3 的图表来比较不同类型)

    【讨论】:

    • 全错了。这些东西都不是字符串。它们都是指针。 -1
    • @LightnessRacesinOrbit 您在技术上是正确的 - 尽管根据我的经验,在 C++ 中引用字符串类型时,为了简洁起见,通常会省略“指向...的指针”描述
    • @JohnSibly:在 C 中,是的。在 C++ 中,绝对不应该!!
    • 请注意,那篇 codeproject 文章是 15 年前写的,除非它得到更新,否则包含关于 Unicode 字符始终为 2 个字节的误导性假设。这是完全错误的。甚至 UTF16 也是可变长度的……最好说宽字符是 UCS-2 编码的,而在这种情况下,“Unicode”指的是 UCS-2。
    • 嗯...在这种情况下,@LightnessRacesinOrbit,我会添加一个附录,在 C++ 中引用 C 字符串时,可以省略“指向...的指针”,如果-并且仅当专门引用(衰减的)字符串文字时,或者在与用 C 编写的代码交互/使用时,依赖于 C 类型而不是 C++ 类型,和/或通过extern "C" 具有 C 链接。除此之外,是的,它肯定需要“指针”位,或者作为 C 字符串的具体描述。
    【解决方案5】:

    要回答问题的第二部分,您需要执行以下操作

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

    因为 MS 的 LVITEM 结构有一个 LPTSTR,即一个 可变 T 字符串指针,而不是一个 LPCTSTR。你正在做的是

    1) 将string(猜测为CString)转换为LPCTSTR(这实际上意味着将其字符缓冲区的地址作为只读指针获取)

    2) 通过丢弃其const-ness 将该只读指针转换为可写指针。

    这取决于dispinfo 用于您的ListView 调用是否有可能最终尝试通过pszText 写入。如果是这样,这可能是一件非常糟糕的事情:毕竟你得到了一个只读指针,然后决定把它当作可写的:也许它是只读的是有原因的!

    如果您正在使用的是CString,您可以选择使用string.GetBuffer()——故意为您提供可写的LPTSTR。然后,如果字符串确实发生了更改,您必须记住致电ReleaseBuffer()。或者您可以分配一个本地临时缓冲区并将字符串复制到那里。

    在 99% 的情况下这是不必要的,将 LPCTSTR 视为 LPTSTR 会起作用...但是有一天,当您最不期待的时候...

    【讨论】:

    • 你应该避免使用 C 风格转换,而是使用 xxx_cast<>()
    • @harper 你说的很对——但我引用了 OP,这就是他要问的代码。如果我自己编写代码,它肯定会使用xxx_cast<>,而不是混合两种不同的基于括号的转换样式!
    【解决方案6】:

    添加到约翰和蒂姆的答案。

    除非您正在为 Win98 编码,否则您应该在应用程序中使用 6 种以上的字符串类型中的两种

    • LPWSTR
    • LPCWSTR

    其余的旨在支持 ANSI 平台或双重编译。这些在今天已经不像过去那么重要了。

    【讨论】:

    • @BlueRaja,我在回答中主要指的是基于 C 的字符串。但是对于 C++,我会避免使用 std::string,因为它仍然是基于 ASCII 的字符串,而是更喜欢 std::wstring
    • 您应该使用 LPTSTR 和 LPCTSTR,除非您直接调用 ASCII (*A) 或 Widechar (*W)​​ 版本的函数。它们是您在编译时指定的任何字符宽度的别名。
    • ...现在微软正在努力使 WinAPI 的*A 版本与 UTF-8 代码页兼容,它们突然变得更加相关。 ;P
    猜你喜欢
    • 2012-05-20
    • 2014-01-17
    • 2012-12-14
    • 1970-01-01
    • 2010-12-11
    • 2015-12-01
    • 2012-10-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多