What is the difference between _tmain() and main() in C++?
如果我使用以下main()方法运行我的C ++应用程序,一切正常:
1 2 3 4 5 6 7 8 9 10 | 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:
1 2 3 4 5 6 7 8 9 10 | 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; } |
它只显示每个参数的第一个字符。
造成这种情况的区别是什么?
C ++中不存在
根据C ++标准,
它有以下两个签名之一:
1 2 | int main(); int main(int argc, char* argv[]); |
Microsoft已添加一个wmain,用以下内容替换第二个签名:
1 | int wmain(int argc, wchar_t* argv[]); |
然后,为了更容易在Unicode(UTF-16)和它们的多字节字符集之间切换,他们定义了
至于你问题的第二部分,拼图的第一部分是你的主要功能是错误的。
现在,在UTF-16中,启用Unicode时Windows使用的字符集,所有ASCII字符都表示为一对字节
并且由于x86 CPU是little-endian,所以这些字节的顺序是交换的,因此ASCII值首先出现,然后是空字节。
在char字符串中,字符串通常如何终止?是的,由空字节组成。所以你的程序会看到一串字符串,每个字节长一个字节。
通常,在进行Windows编程时有三个选项:
-
显式使用Unicode(调用wmain,对于每个采用与char相关的参数的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定义。
_tmain是一个根据您是否使用Unicode或ASCII编译而重新定义的宏。它是Microsoft扩展,不保证可以在任何其他编译器上工作。
正确的声明是
1 | int _tmain(int argc, _TCHAR *argv[]) |
如果定义宏UNICODE,则扩展为
1 | int wmain(int argc, wchar_t *argv[]) |
否则它会扩展到
1 | int main(int argc, char *argv[]) |
您的定义适用于每个,并且(如果您定义了UNICODE)将扩展为
1 | int wmain(int argc, char *argv[]) |
这是完全错误的。
std :: cout适用于ASCII字符。如果使用宽字符,则需要std :: wcout。
尝试这样的事情
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #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",这似乎是最新的时尚。两者都很好。
结束更新
_T约定用于指示程序应使用为应用程序定义的字符集(Unicode,ASCII,MBCS等)。您可以使用_T()包围字符串,以便以正确的格式存储它们。
1 | cout << _T("There are" ) << argc << _T(" arguments:" ) << endl; |
好吧,问题似乎得到了相当好的回答,UNICODE重载应该采用宽字符数组作为其第二个参数。因此,如果命令行参数
所以现在你可能想知道为什么它甚至编译和链接。
好吧它编译因为你被允许定义一个函数的重载。
链接是一个稍微复杂的问题。在C中,没有装饰符号信息,因此它只找到一个名为main的函数。 argc和argv可能总是作为调用堆栈参数存在,以防万一你的函数是用这个签名定义的,即使你的函数碰巧忽略了它们。
即使C ++确实有装饰符号,它几乎肯定会使用C-linkage作为main,而不是依次查找每个符号的聪明链接器。所以它找到了你的wmain并将参数放在call-stack上,以防它是
只需稍微努力将其模板化,就可以使用任何对象列表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #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 << ' '; } |