C ++中的_tmain()和main()之间有什么区别?

如果我使用下面的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; } 

它只显示每个参数的第一个字符。

造成这种情况的区别是什么?

_tmain在C ++中不存在。 main

_tmain是微软的扩展。

main是根据C ++标准,程序的入口点。 它有这两个签名之一:

 int main(); int main(int argc, char* argv[]); 

微软已经添加了一个wmain替​​换第二个签名:

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

然后,为了更容易在Unicode(UTF-16)和它们的多字节字符集之间切换,他们已经定义了_tmain ,如果启用了Unicode,那么编译为wmain ,否则就是main

至于你的问题的第二部分,难题的第一部分是你的主要功能是错误的。 wmain应该采用wchar_t参数,而不是char 。 由于编译器没有main函数强制执行,所以你得到一个程序,在这个程序中,一个wchar_t字符串数组被传递给main函数,并将其解释为char字符串。

现在,在启用Unicode的情况下,在UTF-16中,由Windows使用的字符集,所有ASCII字符都被表示为一对字节\0后跟ASCII值。

而且由于x86 CPU是小端的,所以这些字节的顺序是交换的,所以ASCII值先出现,然后是空字节。

在字符串中,字符串是如何终止的? 是的,由空字节。 所以你的程序看到了一串字符串,每一个字节长。

一般来说,在进行Windows编程时有三个选项:

  • 显式使用Unicode(调用wmain,并且对于每个使用与char相关的参数的Windows API函数,调用函数的-W版本,而不是CreateWindow,请调用CreateWindowW)。 而不是使用char使用wchar_t ,等等
  • 显式禁用Unicode。 调用main和CreateWindowA,并使用字符串作为字符串。
  • 同时允许。 (调用_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进行编译而得到重新定义。 这是一个微软的扩展,并不保证在其他编译器上工作。

正确的声明是

  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”,这似乎是最新的时尚。 两者都很好。

结束更新

_T约定用于表示程序应该使用为应用程序定义的字符集(Unicode,ASCII,MBCS等)。 你可以使用_T()来包围你的字符串,使它们以正确的格式存储。

  cout << _T( "There are " ) << argc << _T( " arguments:" ) << endl; 

好的,这个问题似乎已经得到了很好的回答,UNICODE重载应该将宽字符数组作为第二个参数。 所以如果命令行参数是"Hello" ,可能会最终为"H\0e\0l\0l\0o\0\0\0"并且您的程序只会在打印出'H'一个空终止符。

所以现在你可能想知道为什么它编译和链接。

那么它编译,因为你可以定义一个函数的重载。

链接是一个稍微复杂的问题。 在C中没有装饰的符号信息,所以它只是找到一个叫main的函数。 argc和argv可能总是作为调用堆栈参数,即使您的函数是使用该签名定义的,即使您的函数恰好忽略了它们。

即使C ++有装饰符号,它几乎可以肯定地使用C-linkage作为main,而不是一个聪明的链接器,依次查找每一个。 所以它找到了你的wmain,并把参数放到调用栈中,以防int wmain(int, wchar_t*[])版本。

用一点点的努力来模仿这个,它会用任何物品清单来工作。

 #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() + (js)); ++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'; }