232

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

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

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

4

5 回答 5

368

_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字符串。

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

由于 x86 CPU 是 little-endian,因此这些字节的顺序是交换的,因此 ASCII 值首先出现,然后是空字节。

而在 char 字符串中,字符串通常如何终止?是的,通过一个空字节。因此,您的程序会看到一堆字符串,每个字符串长一个字节。

通常,在进行 Windows 编程时,您有三种选择:

  • 显式使用 Unicode(调用 wmain,并且对于每个接受 char 相关参数的 Windows API 函数,调用-W函数的版本。而不是 CreateWindow,调用 CreateWindowW)。而不是使用charusewchar_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 定义。

于 2009-05-22T00:09:28.873 回答
38

_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”,这似乎是最新的时尚。两者都工作正常。

结束更新

于 2009-05-23T08:39:32.263 回答
9

_T 约定用于指示程序应使用为应用程序定义的字符集(Unicode、ASCII、MBCS 等)。您可以用 _T( ) 将字符串括起来,以使它们以正确的格式存储。

 cout << _T( "There are " ) << argc << _T( " arguments:" ) << endl;
于 2009-05-21T23:47:41.960 回答
6

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

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

好吧,它可以编译,因为您可以定义函数的重载。

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

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

于 2012-10-15T09:30:39.327 回答
-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';
}
于 2017-07-02T09:45:39.633 回答