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++ 等的一些其他调整,包括&lt;windows.h&gt;。然后使用像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() 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

C笔记A01 _tmain() 和 main() 的区别,

wmain _tmain()和main()区别

vs中 main和_tmain的区别

int main() 与 int _tmain()

(转) main(), _tmain(), wmain(), wWinMain(), _tWinMain()的区别

C++ _tmain 不会开始运行