Mic*_*rus 2 c c++ winapi tchar visual-studio
什么是TCHAR字符串,例如LPTSTR和LPCTSTR我如何使用它们?当我在Visual Studio中创建一个新项目时,它为我创建了这个代码:
#include <tchar.h>
int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
例如,我如何连接所有命令行参数?
如果我想打开第一个命令行参数给出的名称的文件,我该怎么做?Windows API定义了许多函数的"A"和"W"版本,例如CreateFile,CreateFileA和CreateFileW; 那么这些如何彼此不同以及我应该使用哪一个?
首先我要说的是,您最好不要使用TCHAR新的Windows项目,而是直接使用Unicode.关于实际答案:
我们需要了解的第一件事是字符集在Visual Studio中的工作原理.项目属性页面有一个选项可以选择使用的字符集:

根据您选择的三个选项中的哪一个,更改了许多定义以适应所选字符集.有三个主要类:字符串,字符串例程tchar.h和API函数:
TCHAR = char使用ANSI编码,其中您使用系统的标准8位代码页作为字符串.所有tchar.h字符串例程都使用基本char版本.所有使用字符串的API函数都将使用API函数的"A"版本.TCHAR = wchar_t使用UTF-16编码.所有tchar.h字符串例程都使用这些wchar_t版本.所有使用字符串的API函数都将使用API函数的"W"版本.TCHAR = char,使用一些多字节编码方案.所有tchar.h字符串例程都使用多字节字符集版本.所有使用字符串的API函数都将使用API函数的"A"版本.相关阅读:关于visual studio 2010中的"字符集"选项
该tchar.h标题是使用通用名称为在字符串中使用C字符串操作,即切换到给定字符集的正确功能的帮手.例如,_tcscat将切换到strcat(未设置),wcscat(unicode)或_mbscat(mbcs)._tcslen将切换到strlen(未设置),wcslen(unicode)或strlen(mbcs).
_txxx根据编译器开关,通过将所有符号定义为评估为正确函数的宏来进行切换.
它背后的想法是你可以使用与编码无关的类型TCHAR(或_TCHAR)以及与它们相关的编码不可知函数tchar.h,而不是常规的字符串函数string.h.
同样,_tmain被定义为main或者wmain.另请参阅: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;
}
Run Code Online (Sandbox Code Playgroud)
(省略了错误检查)此代码适用于字符集的所有三种情况,因为我们使用的任何地方TCHAR,tchar.h字符串函数和_T字符串文字._T(..)在编写此类程序时,忘记包围字符串文字是编译器错误的常见原因TCHAR.如果我们没有完成所有这些事情,那么切换字符集会导致代码无法编译,或者更糟糕的是,编译但在运行时期间行为异常.
在字符串中使用的Windows API函数(例如CreateFile和)GetCurrentDirectory在Windows标头中实现为宏,就像tchar.h宏一样,切换到"A"版本或"W"版本.例如,CreateFile是CreateFileA为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;
}
Run Code Online (Sandbox Code Playgroud)
(省略错误检查)请注意,对于此示例,我们无需使用任何TCHAR特定内容,因为宏定义已经为我们处理了这个问题.
我们已经看到了如何使用tchar.h例程来使用C样式的字符串操作来处理TCHARs,但是如果我们可以利用C++ string来处理它,那就太好了.
我的建议最重要的是不使用TCHAR而是直接使用Unicode,请参阅结论部分,但如果您想与之合作TCHAR,可以执行以下操作.
要使用TCHAR,我们想要的是一个std::basic_string使用的实例TCHAR.您可以通过typedef自己的方式完成此操作tstring:
typedef std::basic_string<TCHAR> tstring;
Run Code Online (Sandbox Code Playgroud)
对于字符串文字,请不要忘记使用_T.
您还需要使用正确版本的cin和cout.您可以使用引用来实现tcin和tcout:
#if defined(_UNICODE)
std::wistream &tcin = wcin;
std::wostream &tcout = wcout;
#else
std::istream &tcin = cin;
std::ostream &tcout = cout;
#end
Run Code Online (Sandbox Code Playgroud)
这应该可以让你几乎做任何事情.可能会偶尔出现异常,例如std::to_string和std::to_wstring,您可以找到类似的解决方法.
这个答案(希望如此)详细说明TCHAR了它与Visual Studio和Windows标头一起使用和交织的内容.但是,我们也应该想知道是否要使用它.
我的建议是直接对所有新的Windows程序使用Unicode,根本不使用TCHAR!
其他人给出了同样的建议:TCHAR仍然具有相关性吗?
要在创建新项目后使用Unicode,请首先确保将字符集设置为Unicode.然后,#include <tchar.h>从源文件中删除(或从中删除stdafx.h).修复的任何TCHAR或_TCHAR到wchar_t和_tmain到wmain:
int wmain(int argc, wchar_t *argv[])
Run Code Online (Sandbox Code Playgroud)
对于非控制台项目,Windows应用程序的入口点将WinMain显示在TCHAR-jargon中
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
Run Code Online (Sandbox Code Playgroud)
并且应该成为
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
Run Code Online (Sandbox Code Playgroud)
在此之后,仅使用wchar_t字符串和/或std::wstrings.
sizeof(szMyString)时使用TCHAR数组(字符串)时要小心,因为对于ANSI,这是字符和字节的大小,对于Unicode,这只是字节大小,字符数最多为一半,对于MBCS,这是大小(以字节为单位)和字符数可能相等也可能不相等.Unicode和MBCS都可以使用多个TCHARs来编码单个字符.TCHAR东西和固定char或wchar_t非常烦人; 你必须使用正确的代码页将字符串从一个转换为另一个!简单副本在一般情况下不起作用._UNICODE和之间存在细微差别UNICODE.请参阅为什么UNICODE和_UNICODE?一个非常好的,互补的答案是:Windows上的MBCS和UTF-8之间的差异
| 归档时间: |
|
| 查看次数: |
1341 次 |
| 最近记录: |