В чем разница между tmain() и main() в C++?

Если я запускаю свое приложение C++ со следующим методом main (), все в порядке:

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

Он просто отображает первый символ каждого аргумента.

какая разница причина?

5 ответов


_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, и иначе как main.

что касается второй части вашего вопроса, первая часть головоломки заключается в том, что ваша главная функция-это неправильно. wmain стоит взять wchar_t аргумент, а не char. Поскольку компилятор не применяет это для main функция, вы получаете программу, где массив wchar_t строки передают main функция, которая интерпретирует их как char строки.

сейчас, в UTF-16, набор символов, используемый Windows, когда Unicode включен, все символы ASCII представлены в виде пары байтов с последующим значением ASCII.

и так как процессор x86 мало-endian, порядок этих байтов меняются местами, так что значение ASCII приходит первым, а затем следует нулевой байт.

и в строке char, как обычно заканчивается строка? Да, нулевым байтом. Таким образом, ваша программа видит кучу строк, каждый байт длинный.

в общем, у вас есть три варианта при программировании Windows:

  • явно используйте Unicode (вызов wmain, и для каждой функции Windows API, которая принимает аргументы, связанные с char, вызовите -W версия функции. Вместо CreateWindow вызовите CreateWindowW). И вместо использования char использовать wchar_t и так далее
  • явно отключить Unicode. Вызовите main и CreateWindowA и используйте char для веревка.
  • разрешить. (вызовите _tmain и CreateWindow, которые разрешают main/_tmain и CreateWindowA / CreateWindowW) и используйте TCHAR вместо char / wchar_t.

то же самое относится к строковым типам, определенным windows.ч: Lpctstr разрешается в LPCSTR или LPCWSTR, и для каждого другого типа, который включает char или wchar_t, всегда существует A-T - версия, которую можно использовать вместо этого.

обратите внимание, что все это специфично для Microsoft. TCHAR не является стандартный тип C++, это макрос, определенный в Windows.h. wmain и _tmain также определяются только Microsoft.


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

или вы можете просто заранее решить, использовать ли широкие или узкие символы. :-)

Обновлено 12 Ноября 2013:

изменен традиционный " TCHAR "на" _TCHAR", который, кажется, является последней модой. Обе работы штраф.

Обновления


соглашение _T используется для указания, что программа должна использовать набор символов, определенный для приложения (Unicode, ASCII,MBCS и т. д.). Вы можете окружить свои строки _T (), чтобы они хранились в правильном формате.

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

Ok, на вопрос, похоже, ответили довольно хорошо, перегрузка UNICODE должна принимать широкий массив символов в качестве второго параметра. Поэтому, если параметр командной строки "Hello" Это, вероятно, закончится как "Hello" и ваша программа будет печатать только в 'H' прежде чем он увидит, что он думает, является нулевым Терминатором.

теперь вы можете задаться вопросом, почему он даже компилируется и ссылки.

Ну, он компилируется, потому что вам разрешено определять перегрузку функции.

связывание-немного более сложная проблема. В C нет информации о украшенном символе, поэтому он просто находит функцию main. Argc и argv, вероятно, всегда существуют как параметры стека вызовов на всякий случай, даже если ваша функция определена с этой сигнатурой, даже если ваша функция игнорирует их.

хотя C++ имеет украшенные символы, он почти наверняка использует C-linkage для main, а не умный компоновщик, который ищет каждый по очереди. Таким образом, он нашел ваш wmain и поместил параметры в стек вызовов, если это int wmain(int, wchar_t*[]) версия.


С небольшим усилием templatizing это, это будет работать с любым списком объектов.

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