如果我用以下main()方法运行我的c++应用程序,一切都是OK的:

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

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

造成这种情况的差异是什么?


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

 cout << _T( "There are " ) << argc << _T( " arguments:" ) << endl;

_tmain在c++中不存在。主要作用。

_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函数,main函数将它们解释为char字符串。

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

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

在char字符串中,字符串通常是如何结束的?是的,通过一个空字节。所以你的程序看到一串字符串,每一个字节长。

一般来说,在进行Windows编程时有三个选项:

显式地使用Unicode(调用wmain,对于每个接受与char相关参数的Windows API函数,调用该函数的-W版本。调用CreateWindowW)而不是CreateWindow。用wchar_t代替char,以此类推 显式禁用Unicode。调用main和CreateWindowA,并对字符串使用char。 允许两个。(调用_tmain和CreateWindow,解析为main/_tmain和CreateWindowA/CreateWindowW),并使用TCHAR代替char/wchar_t。

这同样适用于windows.h定义的字符串类型: LPCTSTR解析为LPCSTR或LPCWSTR,对于包含char或wchar_t的任何其他类型,总是存在一个- t -版本,可以使用它代替。

请注意,所有这些都是微软特有的。TCHAR不是标准的c++类型,它是windows.h中定义的宏。wmain和_tmain也仅由微软定义。


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

最后更新


好了,这个问题似乎已经回答得相当好了,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() + (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';
}