C++ 中的 _tmain() 和 main() 有啥区别?
Posted
技术标签:
【中文标题】C++ 中的 _tmain() 和 main() 有啥区别?【英文标题】:What is the difference between _tmain() and main() in C++?C++ 中的 _tmain() 和 main() 有什么区别? 【发布时间】:2010-10-28 02:32:06 【问题描述】:如果我使用以下 main() 方法运行我的 C++ 应用程序,一切正常:
int main(int argc, char *argv[])
cout << "There are " << argc << " arguments:" << endl;
// Loop through each argument and print its number and value
for (int i=0; i<argc; i++)
cout << i << " " << argv[i] << endl;
return 0;
我得到了我的期望并且我的论点被打印出来了。
但是,如果我使用 _tmain:
int _tmain(int argc, char *argv[])
cout << "There are " << argc << " arguments:" << endl;
// Loop through each argument and print its number and value
for (int i=0; i<argc; i++)
cout << i << " " << argv[i] << endl;
return 0;
它只显示每个参数的第一个字符。
造成这种情况的区别是什么?
【问题讨论】:
【参考方案1】:只需稍作模板化,它就可以处理任何对象列表。
#include <iostream>
#include <string>
#include <vector>
char non_repeating_char(std::string str)
while(str.size() >= 2)
std::vector<size_t> rmlist;
for(size_t i = 1; i < str.size(); i++)
if(str[0] == str[i])
rmlist.push_back(i);
if(rmlist.size())
size_t s = 0; // Need for terator position adjustment
str.erase(str.begin() + 0);
++s;
for (size_t j : rmlist)
str.erase(str.begin() + (j-s));
++s;
continue;
return str[0];
if(str.size() == 1) return str[0];
else return -1;
int main(int argc, char ** args)
std::string test = "FabaccdbefafFG";
test = args[1];
char non_repeating = non_repeating_char(test);
Std::cout << non_repeating << '\n';
【讨论】:
【参考方案2】:_tmain 是一个宏,它会根据您是使用 Unicode 还是 ASCII 编译而重新定义。它是 Microsoft 扩展,不保证适用于任何其他编译器。
正确的声明是
int _tmain(int argc, _TCHAR *argv[])
如果定义了宏 UNICODE,则扩展为
int wmain(int argc, wchar_t *argv[])
否则扩展为
int main(int argc, char *argv[])
您的定义适用于每个,并且(如果您定义了 UNICODE)将扩展为
int wmain(int argc, char *argv[])
这是完全错误的。
std::cout 适用于 ASCII 字符。如果您使用宽字符,则需要 std::wcout。
试试这样的
#include <iostream>
#include <tchar.h>
#if defined(UNICODE)
#define _tcout std::wcout
#else
#define _tcout std::cout
#endif
int _tmain(int argc, _TCHAR *argv[])
_tcout << _T("There are ") << argc << _T(" arguments:") << std::endl;
// Loop through each argument and print its number and value
for (int i=0; i<argc; i++)
_tcout << i << _T(" ") << argv[i] << std::endl;
return 0;
或者您可以提前决定是使用宽字符还是窄字符。 :-)
2013 年 11 月 12 日更新:
将传统的“TCHAR”更改为“_TCHAR”,这似乎是最新的时尚。两者都工作正常。
结束更新
【讨论】:
“它是 Microsoft 扩展,不适用于任何其他编译器。” Not as far as RAD Studio is concerned. @b1naryatr0phy - 要拆分头发,您链接到的工具使用“_TCHAR”,而不是“TCHAR”,因此它不兼容(尽管它确实歪曲了我的说法)。但是我应该说“它是 Microsoft 扩展,不保证可以在任何其他编译器上工作。”。我会修改原来的。 @MichaelJ 我主要指的是“代码更改...”部分,这解释了为什么 RAD Studio 现在使用 _tmain 代替 main,实际上它现在是 Embarcadero 的 C++ 的标准默认值生成器。 这是这个四年前的答案最近第二次被否决。如果反对者发表评论解释他们认为什么问题以及(如果可能的话)如何改进答案,那就太好了。 b1naryatr0phy 发现了一个写得很糟糕的句子,但我在三月份把它修好了。任何指导将不胜感激。 生命太短暂了。【参考方案3】:好的,这个问题似乎已经得到了很好的回答,UNICODE 重载应该将一个宽字符数组作为它的第二个参数。因此,如果命令行参数是"Hello"
,那么它可能会以"H\0e\0l\0l\0o\0\0\0"
结尾,而您的程序只会在看到它认为是空终止符之前打印'H'
。
所以现在你可能想知道为什么它甚至可以编译和链接。
它可以编译,因为你可以定义一个函数的重载。
链接是一个稍微复杂的问题。在 C 中,没有修饰符号信息,所以它只找到一个名为 main 的函数。 argc 和 argv 可能总是作为调用堆栈参数存在,以防万一您的函数是使用该签名定义的,即使您的函数碰巧忽略了它们。
尽管 C++ 确实有修饰符号,但几乎可以肯定它使用 C 链接作为 main,而不是一个聪明的链接器依次查找每个符号。因此它找到了您的 wmain 并将参数放入调用堆栈,以防它是 int wmain(int, wchar_t*[])
版本。
【讨论】:
好的,所以多年来我在将代码移植到 windows widechar 时遇到问题,这是我第一次理解为什么会发生这种情况。来,拿走我所有的名声!哈哈【参考方案4】:_tmain
在 C++ 中不存在。 main
会。
_tmain
是 Microsoft 扩展。
main
根据 C++ 标准,是程序的入口点。
它具有以下两个签名之一:
int main();
int main(int argc, char* argv[]);
Microsoft 添加了一个 wmain,将第二个签名替换为:
int wmain(int argc, wchar_t* argv[]);
然后,为了更容易在 Unicode (UTF-16) 和它们的多字节字符集之间切换,他们定义了 _tmain
,如果启用了 Unicode,则编译为 wmain
,否则编译为 @ 987654330@.
至于你问题的第二部分,谜题的第一部分是你的主要功能是错误的。 wmain
应该采用 wchar_t
参数,而不是 char
。由于编译器不会对main
函数强制执行此操作,因此您会得到一个程序,其中将wchar_t
字符串数组传递给main
函数,该函数将它们解释为char
字符串。
现在,在 UTF-16(启用 Unicode 时 Windows 使用的字符集)中,所有 ASCII 字符都表示为一对字节 \0
后跟 ASCII 值。
由于 x86 CPU 是 little-endian,因此这些字节的顺序是交换的,因此 ASCII 值在前,然后是空字节。
在 char 字符串中,字符串通常如何终止?是的,通过一个空字节。所以你的程序会看到一堆字符串,每个字符串长一个字节。
一般来说,在进行 Windows 编程时,您有三种选择:
显式使用 Unicode(调用 wmain,对于每个采用与字符相关的参数的 Windows API 函数,调用函数的-W
版本。而不是 CreateWindow,调用 CreateWindowW)。而不是使用char
,而是使用wchar_t
,等等
明确禁用 Unicode。调用 main 和 CreateWindowA,并将 char
用于字符串。
两者都允许。 (调用 _tmain 和 CreateWindow,解析为 main/_tmain 和 CreateWindowA/CreateWindowW),并使用 TCHAR 代替 char/wchar_t。
同样适用于 windows.h 定义的字符串类型: LPCTSTR 解析为 LPCSTR 或 LPCWSTR,对于包括 char 或 wchar_t 的所有其他类型,始终存在一个 -T- 版本,可以使用它来代替。
请注意,所有这些都是 Microsoft 特定的。 TCHAR 不是标准的 C++ 类型,它是 windows.h 中定义的宏。 wmain 和 _tmain 也仅由 Microsoft 定义。
【讨论】:
我想知道他们是否也提供 tcout?这样就可以做到 tcout 禁用 UNICODE 会带来什么不利影响? -1 列出的三个选项都不实用。编写 Windows 的实用方法是定义UNICODE
。以及对 C++ 等的一些其他调整,包括<windows.h>
。然后使用像CreateWindow
这样的Unicode函数(通常最后不需要W
)。
为什么你认为这更实用?
"..._tmain 也仅由 Microsoft 定义" 您的最后一段绝对不准确,_tmain 在 RAD Studio 中的实现完全相同C++ 生成器。其实在C++Builder默认的_TCHAR mapping下,单纯使用main会失败。【参考方案5】:
_T 约定用于指示程序应使用为应用程序定义的字符集(Unicode、ASCII、MBCS 等)。您可以用 _T( ) 将字符串括起来,以使它们以正确的格式存储。
cout << _T( "There are " ) << argc << _T( " arguments:" ) << endl;
【讨论】:
事实上,MS 推荐这种方法,afaik。使您的应用程序具有 unicode 感知能力,他们称之为...使用所有字符串操作函数的 _t 版本。 @Deep-B :在 Windows 上,这是您如何使您的应用程序准备好 unicode(我更喜欢 unicode-ready 一词而不是 -aware),如果它之前基于char
s。如果您的应用程序直接使用wchar_t
,那么您的应用程序是 unicode。
顺便说一下,如果您尝试在 UNICODE 上编译,那么您的代码将不会编译为基于字符的 cout 中的输出 wchar_t,它应该是 wcout。有关定义“tcout”的示例,请参见 Michael J 的答案...
None 如果这是微软推荐的,主要是因为它完全是错误的。为 Unicode 编译时,代码将指针值写入标准输出流。 -1.以上是关于C++ 中的 _tmain() 和 main() 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章