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'; }