В чем разница между _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
который, если включен Юникод, компилируется как 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, которая принимает аргументы, связанные с символами, вызовите
-W
версия функции. Вместо CreateWindow, вызовите CreateWindowW). И вместо того, чтобы использоватьchar
использованиеwchar_t
, и так далее - Явно отключить Юникод. Вызовите 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.
_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;
Хорошо, вопрос, кажется, был получен достаточно хорошо, перегрузка 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';
}