什么是TCHAR字符串以及Win32 API函数的“ A”或“ W”版本?

微病毒

什么是TCHAR字符串,如LPTSTRLPCTSTR我怎么能与这些工作?当我在Visual Studio中创建新项目时,它将为我创建以下代码:

#include <tchar.h>

int _tmain(int argc, _TCHAR* argv[])
{
   return 0;
}

例如,如何连接所有命令行参数?

如果要打开第一个命令行参数给定名称的文件,该怎么办?在Windows API定义“A”和它的许多功能,如“W”的版本CreateFileCreateFileACreateFileW; 那么这些之间有什么区别,我应该使用哪一个?

微病毒

首先让我说,您最好不要TCHAR用于新的Windows项目,而应直接使用Unicode。关于实际答案:

字符集

我们需要了解的第一件事是字符集如何在Visual Studio中工作。项目属性页面具有一个选择使用的字符集的选项:

  • 没有设置
  • 使用Unicode字符集
  • 使用多字节字符集

项目属性页-字符集

根据您选择的三个选项中的哪一个,许多定义都会更改以适应所选的字符集。主要分为三类:字符串,来自的字符串例程tchar.h和API函数:

  • “未设置”对应于TCHAR = char使用ANSI编码,其中您将系统的标准8位代码页用于字符串。所有tchar.h字符串例程都使用基本char版本。所有与字符串一起使用的API函数都将使用API​​函数的“ A”版本。
  • “ Unicode”对应于TCHAR = wchar_t使用UTF-16编码。所有tchar.h字符串例程都使用wchar_t版本。所有与字符串一起使用的API函数都将使用API​​函数的“ W”版本。
  • TCHAR = char使用某些多字节编码方案,“多字节”对应于所有tchar.h字符串例程都使用多字节字符集版本。所有与字符串一起使用的API函数都将使用API​​函数的“ A”版本。

相关阅读:关于Visual Studio 2010中的“字符集”选项

TCHAR.h标头

tchar.h标题是使用通用名称为在字符串中使用C字符串操作,即切换到给定字符集的正确功能的帮手。例如,_tcscat将切换为strcat(未设置),wcscat(unicode)或_mbscat(mbcs)。_tcslen将切换为strlen(未设置),wcslen(unicode)或strlen(mbcs)。

通过将所有_txxx符号定义为可评估正确功能的宏来进行切换,具体取决于编译器的切换。

其背后的想法是,您可以使用from而不是常规字符串函数from来使用与编码无关的类型TCHAR(或_TCHAR)和对它们进行编码的不可知函数tchar.hstring.h

同样,_tmain被定义为mainwmain另请参见:C ++中_tmain()和main()有什么区别?

_T(..)定义了一个辅助宏,用于获取正确类型的字符串文字("regular literals"或)L"wchar_t literals"

请参阅此处提到的警告:TCHAR是否仍然有用?-dan04的答案

_tmain 例子

对于问题中的main的示例,以下代码将所有作为命令行参数传递的字符串连接在一起。

int _tmain(int argc, _TCHAR *argv[])
{
   TCHAR szCommandLine[1024];

   if (argc < 2) return 0;

   _tcscpy(szCommandLine, argv[1]);
   for (int i = 2; i < argc; ++i)
   {
       _tcscat(szCommandLine, _T(" "));
       _tcscat(szCommandLine, argv[i]);
   }

   /* szCommandLine now contains the command line arguments */

   return 0;
}

(省略了错误检查)此代码适用于字符集的所有三种情况,因为在我们使用过的所有地方TCHARtchar.h字符串函数都_T适用于字符串文字。_T(..)编写此类程序时,忘记用字符串文字包围是编译器错误的常见原因TCHAR如果我们还没有做完所有这些事情,那么切换字符集将导致代码在运行时无法编译,或者更糟糕的是编译但行为异常。

Windows API函数

在字符串上工作的Windows API函数(例如CreateFile和)GetCurrentDirectory在Windows标头中作为宏(如tchar.h宏)切换为“ A”版或“ W”版实现。例如,CreateFileCreateFileA为ANSI和MBCS和CreateFileWUnicode定义的宏

每当您在代码中使用平面形式(不带“ A”或“ W”)时,实际调用的函数将根据所选字符集进行切换。您可以通过使用显式的“ A”或“ W”名称来强制使用特定版本。

结论是,除非应始终引用特定版本,否则应始终使用非限定名称,而与字符集选项无关。

对于问题中的示例,我们要在其中打开第一个参数给出的文件:

int _tmain(int argc, _TCHAR *argv[])
{  
   if (argc < 2) return 1;

   HANDLE hFile = CreateFile(argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);

   /* Read from file and do other stuff */
   ...

   CloseHandle(hFile);

   return 0;
}

(省略了错误检查)请注意,在此示例中,我们不需要使用任何TCHAR特定的东西,因为宏定义已经为我们解决了这一问题。

使用C ++字符串

我们已经看到了如何使用tchar.h例程来使用C样式字符串操作来与TCHARs一起工作,但是如果我们可以利用C ++string来与之一起工作,那将是很好的

我的建议最重要的是不要使用TCHAR,而是直接使用Unicode,请参阅“结论”部分,但是如果您想使用TCHAR它,可以执行以下操作。

为了使用TCHAR,我们要的是一个实例std::basic_string使用TCHAR你可以做到这一点typedef荷兰国际集团自己tstring

typedef std::basic_string<TCHAR> tstring;

对于字符串文字,请不要忘记使用_T

您还需要使用的正确版本cincout您可以使用引用来实现tcintcout

#if defined(_UNICODE)
std::wistream &tcin = wcin;
std::wostream &tcout = wcout;
#else
std::istream &tcin = cin;
std::ostream &tcout = cout;
#end

这应该使您几乎可以做任何事情。偶尔会有例外,例如std::to_stringstd::to_wstring,您可以找到类似的解决方法。

结论

这个答案(希望如此)详细说明了什么TCHAR是它,以及如何与Visual Studio和Windows标头结合使用。但是,我们还应该怀疑是否要使用它。

我的建议是直接对所有新的Windows程序使用Unicode,并且根本不要使用Unicode TCHAR

其他人也给出相同的建议:TCHAR是否仍然有用?

要在创建新项目后使用Unicode,请首先确保将字符集设置为Unicode。然后,#include <tchar.h>从您的源文件(或从中stdafx.h删除修复的任何TCHAR_TCHARwchar_t_tmainwmain

int wmain(int argc, wchar_t *argv[])

对于非控制台项目,Windows应用程序的入口点是WinMain并且将在TCHAR-jargon中显示

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR    lpCmdLine, int nCmdShow)

并且应该成为

int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR    lpCmdLine, int nCmdShow)

此后,仅使用wchar_t字符串和/或std::wstrings。

进一步警告

  • sizeof(szMyString)使用TCHAR数组(字符串)时编写要小心,因为对于ANSI,这是字符和字节的大小;对于Unicode,这只是字节的大小,字符数最多为一半;对于MBCS,这是最大字符数。字节大小和字符数可以相等或可以不相等。Unicode和MBCS都可以使用多个TCHAR来编码单个字符。
  • TCHAR东西和固定的东西在一起charwchar_t很烦人;您必须使用正确的代码页将字符串从一个转换为另一个!在一般情况下,简单的副本将不起作用。
  • 如果要有条件地定义自己的函数,则_UNICODE与和之间会有细微的差别UNICODE请参阅为什么同时使用UNICODE和_UNICODE?

一个很好的补充答案是:Windows上的MBCS和UTF-8之间的区别

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何从MFC应用程序调用函数的Win32 API版本?

来自分类Dev

如何从MFC应用程序调用函数的Win32 API版本?

来自分类Dev

是否有Win32 API在字符串中添加双引号?

来自分类Dev

Win32 API函数GetExplicitEntriesFromAcl()的对应项是什么?

来自分类Dev

Win32中有任何易于使用的哈希函数来哈希ASCII字符串吗?

来自分类Dev

调用win32 API并回调类函数

来自分类Dev

为什么在 WIN32 项目中需要 MyRegisterClass() 函数?

来自分类Dev

GetMenuBarInfo()Win32函数

来自分类Dev

为什么我的函数会返回未定义以及反向字符串

来自分类Dev

win32api.ShellExecute()函数做什么?

来自分类Dev

敲除数据绑定文本到函数正在返回函数的字符串化版本

来自分类Dev

什么是Azure API版本

来自分类Dev

Win32 API中的RemoveDirectory()函数在删除子目录后不会删除父目录

来自分类Dev

Perl Win32 :: API-在与DLL函数之间来回传递数组时出现问题

来自分类Dev

作为 DWORD 传递给 WIN32 API 函数 MonitorFromWindow 的值

来自分类Dev

如何创建采用Any类型并输出JSON字符串化版本的函数?

来自分类Dev

从Julia调用Win32函数

来自分类Dev

在Scala中,以字符串到案例类的映射以及以这些案例类作为输入参数的从字符串到函数的映射的类型应该是什么?

来自分类Dev

从LLVM调用Win32 / 64函数的正确方法是什么?

来自分类Dev

当我使用参数调用Win32函数时,为什么GCC使用帧指针?

来自分类Dev

GetGuiResources WIn32 API使用

来自分类Dev

如何禁用按钮-Win32 API

来自分类Dev

Win32 API SearchPath失败

来自分类Dev

GetGuiResources WIn32 API使用

来自分类Dev

Java到Win32加密API

来自分类Dev

Win32 API 无法 CreateWindowW()

来自分类Dev

Gradle函数根据设备API级别更改依赖项版本

来自分类Dev

API网关调用了我的lambda函数的旧版本

来自分类Dev

maya.api.openMaya setWeight 未调用正确版本的函数

Related 相关文章

  1. 1

    如何从MFC应用程序调用函数的Win32 API版本?

  2. 2

    如何从MFC应用程序调用函数的Win32 API版本?

  3. 3

    是否有Win32 API在字符串中添加双引号?

  4. 4

    Win32 API函数GetExplicitEntriesFromAcl()的对应项是什么?

  5. 5

    Win32中有任何易于使用的哈希函数来哈希ASCII字符串吗?

  6. 6

    调用win32 API并回调类函数

  7. 7

    为什么在 WIN32 项目中需要 MyRegisterClass() 函数?

  8. 8

    GetMenuBarInfo()Win32函数

  9. 9

    为什么我的函数会返回未定义以及反向字符串

  10. 10

    win32api.ShellExecute()函数做什么?

  11. 11

    敲除数据绑定文本到函数正在返回函数的字符串化版本

  12. 12

    什么是Azure API版本

  13. 13

    Win32 API中的RemoveDirectory()函数在删除子目录后不会删除父目录

  14. 14

    Perl Win32 :: API-在与DLL函数之间来回传递数组时出现问题

  15. 15

    作为 DWORD 传递给 WIN32 API 函数 MonitorFromWindow 的值

  16. 16

    如何创建采用Any类型并输出JSON字符串化版本的函数?

  17. 17

    从Julia调用Win32函数

  18. 18

    在Scala中,以字符串到案例类的映射以及以这些案例类作为输入参数的从字符串到函数的映射的类型应该是什么?

  19. 19

    从LLVM调用Win32 / 64函数的正确方法是什么?

  20. 20

    当我使用参数调用Win32函数时,为什么GCC使用帧指针?

  21. 21

    GetGuiResources WIn32 API使用

  22. 22

    如何禁用按钮-Win32 API

  23. 23

    Win32 API SearchPath失败

  24. 24

    GetGuiResources WIn32 API使用

  25. 25

    Java到Win32加密API

  26. 26

    Win32 API 无法 CreateWindowW()

  27. 27

    Gradle函数根据设备API级别更改依赖项版本

  28. 28

    API网关调用了我的lambda函数的旧版本

  29. 29

    maya.api.openMaya setWeight 未调用正确版本的函数

热门标签

归档