【问题标题】: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;
}

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

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

【问题讨论】:

    标签: c++ unicode arguments


    【解决方案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.
      猜你喜欢
      • 2011-10-18
      • 2019-07-11
      • 1970-01-01
      • 2011-01-27
      • 2021-07-29
      • 1970-01-01
      • 2014-02-22
      • 1970-01-01
      • 2011-05-10
      相关资源
      最近更新 更多