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

Если я запустил свое приложение на С++ со следующим методом 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;
}

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

В чем разница, вызывающая это?

Ответ 1

_tmain не существует в С++. main делает.

_tmain - расширение Microsoft.

main соответствует стандарту С++, точке входа в программу. Он имеет одну из этих двух подписей:

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 представлены как пара байтов \0, за которыми следует значение ASCII.

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

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

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

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

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

Обратите внимание, что все это зависит от Microsoft. TCHAR не является стандартным типом С++, это макрос, определенный в windows.h. wmain и _tmain также определяются только Microsoft.

Ответ 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;
}

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

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

Изменен традиционный "TCHAR" на "_TCHAR", который, по-видимому, является последним модом. Оба работают нормально.

Окончательное обновление

Ответ 3

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

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

Ответ 4

Хорошо, вопрос, как представляется, был удовлетворен достаточно хорошо, перегрузка UNICODE должна принимать широкий массив символов в качестве второго параметра. Поэтому, если параметр командной строки "Hello", который, вероятно, заканчивается как "H\0e\0l\0l\0o\0\0\0", и ваша программа будет печатать только 'H', прежде чем он увидит, что он считает нулевым терминатором.

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

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

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

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

Ответ 5

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

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