В чем разница между _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';
}