关于unicode:C ++中_tmain()和main()有什么区别?

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 ++中不存在_tmainmain

_tmain是Microsoft扩展。

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

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

Microsoft已添加一个wmain,用以下内容替换第二个签名:

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

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

至于你问题的第二部分,拼图的第一部分是你的主要功能是错误的。 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,对于每个采用与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重载应该采用宽字符数组作为其第二个参数。因此,如果命令行参数"Hello"可能最终为"H\0e\0l\0l\0o\0\0\0",并且您的程序只会在它看到它认为是空终止符之前打印'H'

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

好吧它编译因为你被允许定义一个函数的重载。

链接是一个稍微复杂的问题。在C中,没有装饰符号信息,因此它只找到一个名为main的函数。 argc和argv可能总是作为调用堆栈参数存在,以防万一你的函数是用这个签名定义的,即使你的函数碰巧忽略了它们。

即使C ++确实有装饰符号,它几乎肯定会使用C-linkage作为main,而不是依次查找每个符号的聪明链接器。所以它找到了你的wmain并将参数放在call-stack上,以防它是int wmain(int, wchar_t*[])版本。


只需稍微努力将其模板化,就可以使用任何对象列表。

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