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