web-dev-qa-db-ja.com

C ++の_tmain()とmain()の違いは何ですか?

次のmain()メソッドを使用してC++アプリケーションを実行すると、すべて問題ありません。

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

各引数の最初の文字を表示するだけです。

これを引き起こす違いは何ですか?

218
joshcomley

_tmainはC++には存在しません。 mainはそうします。

_tmainはMicrosoftの拡張機能です。

mainは、C++標準に従って、プログラムのエントリポイントです。次の2つの署名のいずれかがあります。

int main();
int main(int argc, char* argv[]);

Microsoftは、2番目の署名をこれに置き換えるwmainを追加しました。

int wmain(int argc, wchar_t* argv[]);

そして、ユニコード(UTF-16)とマルチバイト文字セットを簡単に切り替えるために、ユニコードが有効な場合はwmainとしてコンパイルされ、そうでない場合はmainとしてコンパイルされる_tmainを定義しました。

質問の2番目の部分については、パズルの最初の部分は、あなたの主な機能が間違っているということです。 wmainは、charではなく、wchar_t引数を取る必要があります。コンパイラはmain関数に対してこれを強制しないため、wchar_t文字列の配列がmain関数に渡され、char関数として解釈されるプログラムを取得します。

現在、Unicodeが有効な場合にWindowsで使用される文字セットであるUTF-16では、すべてのASCII文字は、バイトのペア\0に続いてASCII値として表されます。

また、x86 CPUはリトルエンディアンであるため、これらのバイトの順序が入れ替わり、ASCII値が最初に来て、次にヌルバイトが続きます。

また、文字列では、通常、文字列はどのように終了しますか?はい、nullバイトです。したがって、プログラムは、それぞれが1バイト長の文字列の束を認識します。

一般に、Windowsプログラミングを行う場合、次の3つのオプションがあります。

  • 明示的にUnicodeを使用します(wmainを呼び出します。char関連の引数を受け取るすべてのWindows API関数については、関数の-Wバージョンを呼び出します。CreateWindowの代わりにCreateWindowWを呼び出します)。そして、charを使用する代わりにwchar_tを使用するなど
  • Unicodeを明示的に無効にします。 mainおよびCreateWindowAを呼び出し、文字列にcharを使用します。
  • 両方を許可します。 (main/_tmainおよびCreateWindowA/CreateWindowWに解決される_tmainおよびCreateWindowを呼び出します)、char/wchar_tの代わりにTCHARを使用します。

Windows.hで定義された文字列型にも同じことが当てはまります。LPCTSTRはLPCSTRまたはLPCWSTRに解決され、charまたはwchar_tを含む他のすべての型には、代わりに使用できる-T-バージョンが常に存在します。

これらはすべてMicrosoft固有のものであることに注意してください。 TCHARは標準のC++型ではなく、windows.hで定義されたマクロです。 wmainと_tmainもMicrosoftによってのみ定義されています。

343
jalf

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

または、ワイド文字を使用するか狭い文字を使用するかを事前に決定することもできます。 :-)

2013年11月12日に更新:

従来の「TCHAR」を「_TCHAR」に変更しました。これは最新のファッションのようです。両方ともうまくいきます。

更新の終了

34
Michael J

_T規則は、プログラムがアプリケーション用に定義された文字セット(Unicode、ASCII、MBCSなど)を使用する必要があることを示すために使用されます。文字列を_T()で囲んで、正しい形式で保存できます。

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

OK、質問はかなりよく答えられたようです。UNICODEオーバーロードは、2番目のパラメーターとしてワイド文字配列を取る必要があります。そのため、コマンドラインパラメーターが"Hello"である場合、おそらく"H\0e\0l\0l\0o\0\0\0"になり、プログラムは、'H'のみを出力し、それがnullターミネーターであると判断する前に表示します。

それで、なぜコンパイルしてリンクするのか不思議に思うかもしれません。

関数にオーバーロードを定義できるため、コンパイルできます。

リンクはもう少し複雑な問題です。 Cでは、装飾されたシンボル情報がないため、mainという関数が検出されます。 argcとargvは、関数がそのシグネチャで定義されている場合でも、関数がそれらを無視した場合でも、おそらく呼び出しスタックパラメータとして常に存在します。

C++には装飾されたシンボルがありますが、ほとんど確実に、それぞれを順番に検索する賢いリンカーではなく、mainにCリンケージを使用します。したがって、int wmain(int, wchar_t*[])バージョンの場合、wmainを検出し、呼び出しスタックにパラメーターを配置します。

5
CashCow