C ++ 'da _tmain () ve main () arasındaki fark nedir?


224

C ++ uygulamamı aşağıdaki main () yöntemiyle çalıştırırsam her şey yolunda demektir:

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

Beklediğimi anladım ve argümanlarım çıktı.

Ancak, _tmain kullanırsanız:

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

Her argümanın ilk karakterini görüntüler.

Buna neden olan fark nedir?

Yanıtlar:


357

_tmainC ++ 'da mevcut değildir. mainyapar.

_tmain bir Microsoft uzantısıdır.

mainC ++ standardına göre, programın giriş noktasıdır. Bu iki imzadan birine sahiptir:

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

Microsoft, ikinci imzayı bununla değiştiren bir wmain ekledi:

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

Ve sonra, Unicode (UTF-16) ve çok baytlı karakter kümeleri arasında geçiş yapmayı kolaylaştırmak için _tmain, Unicode etkinleştirilirse, olarak wmainve başka bir şekilde derlendiğini tanımladılar main.

Sorunuzun ikinci kısmına gelince, bulmacanın ilk kısmı ana işlevinizin yanlış olmasıdır. wmainBir almalı wchar_t, argüman değil char. Derleyici mainişlev için bunu zorlamadığından, işleve bir dizi wchar_tdizenin geçtiği ve mainbunları chardizgi olarak yorumlayan bir program alırsınız .

Şimdi, UTF-16'da, Unicode etkinleştirildiğinde Windows tarafından kullanılan karakter kümesi, tüm ASCII karakterleri bayt çifti ve \0ardından ASCII değeri olarak temsil edilir .

Ve x86 CPU küçük endian olduğundan, bu baytların sırası değiştirilir, böylece ASCII değeri önce gelir, ardından boş bir bayt gelir.

Ve bir karakter dizesinde, karakter dizisi genellikle nasıl sonlandırılır? Evet, boş bir bayt tarafından. Programınız her biri bayt uzunluğunda bir dizi dizgi görür.

Genel olarak, Windows programlama yaparken üç seçeneğiniz vardır:

  • Unicode'u açıkça kullanın (wmain'i çağırın ve karakterle ilgili bağımsız değişkenleri alan her Windows API işlevi -Wiçin işlevin sürümünü çağırın . CreateWindow yerine CreateWindowW çağırın). Ve kullanmak yerine charkullanılmasını wchar_tve benzeri
  • Unicode'u açıkça devre dışı bırakın. Main ve CreateWindowA öğelerini çağırın ve chardizeler için kullanın .
  • Her ikisine de izin ver. (_tmain ve main / _tmain ve CreateWindowA / CreateWindowW için çözümlenen CreateWindow'u çağırın) ve char / wchar_t yerine TCHAR kullanın.

Aynısı windows.h tarafından tanımlanan dize türleri için de geçerlidir: LPCTSTR, LPCSTR veya LPCWSTR olarak çözümlenir ve char veya wchar_t içeren diğer tüm türler için her zaman bunun yerine kullanılabilecek bir -T- sürümü vardır.

Tüm bunların Microsoft'a özgü olduğunu unutmayın. TCHAR standart bir C ++ türü değil, windows.h dosyasında tanımlanan bir makrodur. wmain ve _tmain yalnızca Microsoft tarafından tanımlanır.


6
ben de bir tcout sağlamak merak ediyorum? böylece tcout << argv [n] yapabilirdi; ve Ansi'de cout ve Unicode modunda wcout çözüyor? Bunun bu durumda onun için yararlı olabileceğinden şüpheleniyorum. ve +1 tabii ki, güzel cevap :)
Johannes Schaub - litb

1
UNICODE'un devre dışı bırakılması hangi dezavantajları sağlar?
joshcomley

2
-1 Listelenen üç seçenekten hiçbiri pratik değildir. Windows'u programlamanın pratik yolu tanımlamaktır UNICODE. Ve dahil etmeden önce C ++ vb <windows.h>. Sonra Unicode işlevlerini aşağıdaki gibi kullanın CreateWindow( Wgenellikle sonunda gerek yok ).
Şerefe ve s. - Alf

11
Neden bunu daha pratik buluyorsunuz?
jalf

1
"..._ tmain de yalnızca Microsoft tarafından tanımlanır" Son paragrafınız kesinlikle yanlış , _tmain RAD Studio'nun C ++ Builder'ında tamamen aynı şekilde uygulanmış. Aslında, C ++ Builder'ın varsayılan _TCHAR eşlemesi altında , basitçe main kullanmak başarısız olur.
b1nary.atr0phy

35

_tmain, Unicode veya ASCII ile derleyip derlememenize bağlı olarak yeniden tanımlanan bir makrodur. Bu bir Microsoft uzantısıdır ve diğer derleyiciler üzerinde çalışacağı garanti edilmez.

Doğru beyan

 int _tmain(int argc, _TCHAR *argv[]) 

UNICODE makrosu tanımlanmışsa,

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

Aksi takdirde

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

Tanımınız her biri için geçerlidir ve (UNICODE tanımlıysa)

 int wmain(int argc, char *argv[])

ki bu sadece yanlıştır.

std :: cout ASCII karakterleriyle çalışır. Geniş karakterler kullanıyorsanız std :: wcout'a ihtiyacınız var.

böyle bir şey dene

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

Veya önceden geniş veya dar karakterler kullanıp kullanmayacağınıza önceden karar verebilirsiniz. :-)

Güncelleme 12 Kasım 2013:

Geleneksel "TCHAR" ı son moda gibi görünen "_TCHAR" olarak değiştirdi. Her ikisi de iyi çalışıyor.

Güncellemeyi Sonlandır


1
"Bu bir Microsoft uzantısıdır ve başka derleyiciler üzerinde çalışmaz." RAD Studio söz konusu olduğunda değil.
b1nary.atr0phy

@ b1naryatr0phy - Kılları bölmek için, bağladığınız araç "TCHAR" yerine "_TCHAR" kullanır, bu yüzden uyumlu değildir (ifademi yanlış yapar). Ancak "Bu bir Microsoft uzantısıdır ve diğer derleyiciler üzerinde çalışacağı garanti edilmez" demeliydim. Orijinali değiştireceğim.
Michael J

@MichaelJ RAD Studio'nun neden şimdi ana yerine _tmain kullandığını açıklayan "Kod Değişiklikleri ..." bölümüne atıfta bulunuyordum ve aslında Embarcadero'nun C ++ Builder'ı için standart varsayılan.
b1nary.atr0phy

1
Geçenlerde bu dört yaşındaki cevap ikinci kez reddedildi. Downvoters, hangi sorunları algıladıklarını ve (mümkünse) cevabı nasıl geliştireceklerini açıklayan bir yorum yapsaydı iyi olurdu. b1naryatr0phy kötü yazılmış bir cümle buldu, ama bunu Mart ayında düzelttim. Herhangi bir rehberlik takdir edilecektir.
Michael J

2
Hayat bunun için çok kısa.
Michael J

10

_T kuralı, programın uygulama için tanımlanan karakter kümesini (Unicode, ASCII, MBCS, vb.) kullanması gerektiğini belirtmek için kullanılır. Doğru biçimde depolanması için dizelerinizi _T () ile çevreleyebilirsiniz.

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

Aslında, MS bu yaklaşımı önerir, afaik. Uygulamanızı unicode-farkında kılmak, tüm dize düzenleme işlevlerinin _t sürümünü kullanarak da çağırırlar.
Deep-B

1
Derin-B @: Ve Windows üzerinde, bu ise o dayanıyordu eğer, (ben unicode hazır-uyumlu bir ila terimi tercih) Başvurunuz unicode hazır hale nasıl charönce s. Başvurunuz doğrudan kullanıyorsa wchar_to zaman uygulama olduğunu unicode.
paercebal

5
Bu arada, UNICODE üzerinde derlemeye çalışırsanız, kodunuz, wcout olması gereken bir char tabanlı cout içinde çıkış wchar_t olarak derlenmez. Michael J'nin "tcout" un tanımlanmasına ilişkin bir cevaba bakınız ...
paercebal

1
Bu, büyük ölçüde Microsoft tarafından öneriliyorsa, büyük ölçüde yanlıştır. Unicode için derleme yaparken, kod işaretçi değerlerini standart çıktı akışına yazar. -1.
IInspectable

5

Tamam, soru oldukça iyi yanıtlanmış gibi görünüyor, UNICODE aşırı yüklenmesi ikinci parametre olarak geniş bir karakter dizisi almalıdır. Komut satırı parametresi "Hello"muhtemelen bu şekilde sonlanırsa "H\0e\0l\0l\0o\0\0\0"ve programınız yalnızca 'H'boş bir sonlandırıcı olduğunu düşündüğü şeyi görmeden basarsa.

Şimdi neden derlendiğini ve bağlantılarını bile merak edebilirsiniz.

Derler çünkü bir fonksiyona aşırı yük tanımlamanıza izin verilir.

Bağlama biraz daha karmaşık bir konudur. C'de, dekore edilmiş sembol bilgisi yoktur, bu yüzden sadece main adı verilen bir işlev bulur. Argc ve argv, işleviniz bu imzayla tanımlanmış olsa bile, işleviniz yoksayılsa bile, her zaman çağrı yığını parametreleri olarak bulunur.

C ++ dekore edilmiş sembollere sahip olsa da, neredeyse her birini sırayla arayan akıllı bir bağlayıcı yerine ana için C-bağlantısı kullanır. Bu yüzden wmain'inizi buldu ve int wmain(int, wchar_t*[])sürüm olması durumunda parametreleri çağrı yığınına koydu .


Tamam, şimdi kodlarımı windows widechar için yıllardır taşıma sorunum var ve bu ilk kez bunun neden olduğunu anladım. İşte, tüm itibarımı al! haha
Leonel

-1

Bunu biraz değiştirmek için, herhangi bir nesne listesiyle çalışmaya başlayacaktır.

#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';
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.