Qual è la differenza tra _tmain () e main () in C ++?

Se eseguo la mia applicazione C ++ con il seguente metodo main () tutto è OK:

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

Ottengo ciò che mi aspetto e i miei argomenti vengono stampati.

Tuttavia, se uso _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; } 

Visualizza solo il primo carattere di ogni argomento.

Qual è la differenza che causa questo?

_tmain non esiste in C ++. main fa.

_tmain è un’estensione Microsoft.

main è, secondo lo standard C ++, il punto di ingresso del programma. Ha una di queste due firme:

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

Microsoft ha aggiunto un wmain che sostituisce la seconda firma con questo:

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

Quindi, per semplificare il passaggio tra Unicode (UTF-16) e il loro set di caratteri multibyte, hanno definito _tmain che, se Unicode è abilitato, viene compilato come wmain , e altrimenti come main .

Per quanto riguarda la seconda parte della tua domanda, la prima parte del puzzle è che la tua funzione principale è sbagliata. wmain dovrebbe prendere un argomento wchar_t , non char . Poiché il compilatore non impone questo per la funzione main , si ottiene un programma in cui una serie di stringhe wchar_t viene passata alla funzione main , che li interpreta come stringhe di char .

Ora, in UTF-16, il set di caratteri utilizzato da Windows quando Unicode è abilitato, tutti i caratteri ASCII sono rappresentati come la coppia di byte \0 seguita dal valore ASCII.

E poiché la CPU x86 è little-endian, l’ordine di questi byte viene scambiato, quindi il valore ASCII viene prima, seguito da un byte null.

E in una stringa di caratteri, come viene terminata la stringa? Sì, con un byte null. Quindi il tuo programma vede un mucchio di stringhe, ognuna lunga un byte.

In generale, hai tre opzioni quando esegui la programmazione Windows:

  • Utilizza in modo esplicito Unicode (chiama wmain e, per ogni funzione API di Windows che accetta argomenti relativi al char, chiama la versione -W della funzione, invece di CreateWindow, chiama CreateWindowW). E invece di usare char usa wchar_t , e così via
  • Disabilita esplicitamente Unicode. Chiama main e CreateWindowA e utilizza char per le stringhe.
  • Consentire entrambi. (chiama _tmain e CreateWindow, che si risolvono in main / _tmain e CreateWindowA / CreateWindowW), e usa TCHAR invece di char / wchar_t.

Lo stesso vale per i tipi di stringhe definiti da windows.h: LPCTSTR si risolve in LPCSTR o LPCWSTR, e per ogni altro tipo che include char o wchar_t, esiste sempre una versione -T- che può essere usata.

Nota che tutto ciò è specifico di Microsoft. TCHAR non è un tipo C ++ standard, è una macro definita in windows.h. wmain e _tmain sono anche definiti solo da Microsoft.

_tmain è una macro che viene ridefinita a seconda che si compili o meno con Unicode o ASCII. È un’estensione Microsoft e non è garantito il funzionamento su altri compilatori.

La dichiarazione corretta è

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

Se la macro UNICODE è definita, che si espande in

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

Altrimenti si espande

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

La tua definizione va per un po ‘di ciascuna, e (se hai definito UNICODE) si espanderà a

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

che è semplicemente sbagliato.

std :: cout funziona con caratteri ASCII. Hai bisogno di std :: wcout se usi caratteri ampi.

provare qualcosa di simile

 #include  #include  #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 

Oppure potresti decidere in anticipo se utilizzare caratteri ampi o stretti. 🙂

Aggiornato il 12 novembre 2013:

Modificato il tradizionale "TCHAR" in "_TCHAR" che sembra essere l'ultima moda. Entrambi funzionano bene.

Fine aggiornamento

la convenzione _T viene utilizzata per indicare che il programma deve utilizzare il set di caratteri definito per l’applicazione (Unicode, ASCII, MBCS, ecc.). È ansible circondare le stringhe con _T () per memorizzarle nel formato corretto.

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

Ok, sembra che la domanda abbia avuto una risposta abbastanza buona, il sovraccarico UNICODE dovrebbe assumere un array di caratteri ampio come secondo parametro. Quindi, se il parametro della riga di comando è "Hello" questo probabilmente finirà con "H\0e\0l\0l\0o\0\0\0" e il tuo programma stamperà solo la 'H' prima di vedere ciò che pensa sia un terminatore nullo.

Quindi ora potresti chiedertene perché compili anche i link.

Bene, compila perché ti è permesso definire un sovraccarico di una funzione.

Il collegamento è un problema leggermente più complesso. In C, non ci sono informazioni sui simboli decorati, quindi trova solo una funzione chiamata main. L’argc e l’argv sono probabilmente sempre presenti come parametri call-stack nel caso in cui anche se la tua funzione è definita con quella firma, anche se la tua funzione capita di ignorarli.

Anche se C ++ ha simboli decorati, utilizza quasi certamente C-linkage per il main, piuttosto che un linker intelligente che cerca a turno ciascuno di essi. Quindi ha trovato il tuo wmain e ha inserito i parametri nello stack di chiamata nel caso fosse la versione int wmain(int, wchar_t*[]) .

Con un piccolo sforzo di templatizzare questo, funziona con qualsiasi lista di oggetti.

 #include  #include  #include  char non_repeating_char(std::string str){ while(str.size() >= 2){ std::vector 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() + (js)); ++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'; }