Si j'exécute mon application C++ avec la méthode main () suivante, tout est 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;
}
Je reçois ce que j'attends et mes arguments sont imprimés.
Cependant, si j'utilise _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;
}
Il affiche simplement le premier caractère de chaque argument.
Quelle est la différence causant ceci?
_tmain
n'existe pas en C++. main
fait.
_tmain
est une extension Microsoft.
main
est, selon la norme C++, le point d'entrée du programme. Il a l'une de ces deux signatures:
int main();
int main(int argc, char* argv[]);
Microsoft a ajouté un wmain qui remplace la deuxième signature par ceci:
int wmain(int argc, wchar_t* argv[]);
Ensuite, pour faciliter le basculement entre Unicode (UTF-16) et leur jeu de caractères multi-octets, ils ont défini _tmain
qui, si Unicode est activé, est compilé sous le nom wmain
et sinon sous la forme main
.
En ce qui concerne la deuxième partie de votre question, la première partie du puzzle est que votre fonction principale est mauvaise. wmain
devrait prendre un argument wchar_t
, et non char
. Comme le compilateur ne l'applique pas pour la fonction main
, vous obtenez un programme dans lequel un tableau de chaînes wchar_t
est transmis à la fonction main
qui les interprète comme des chaînes char
.
Maintenant, dans UTF-16, le jeu de caractères utilisé par Windows lorsque Unicode est activé, tous les caractères ASCII sont représentés par la paire d'octets \0
suivi du caractère ASCII. valeur.
Et puisque le processeur x86 est un petit bout, l'ordre de ces octets est inversé, de sorte que la valeur ASCII vienne en premier, suivie d'un octet nul.
Et dans une chaîne de caractères, comment la chaîne se termine-t-elle généralement? Oui, par octet nul. Ainsi, votre programme voit un tas de chaînes, chacune sur un octet.
En général, vous avez trois options pour programmer en Windows:
-W
de la fonction. Au lieu de CreateWindow, appelez CreateWindowW). Et au lieu d'utiliser char
, utilisez wchar_t
, etc.char
pour les chaînes.La même chose s'applique aux types de chaînes définis par windows.h: LPCTSTR est résolu en LPCSTR ou en LPCWSTR, et pour tout autre type incluant char ou wchar_t, il existe toujours une version -T qui peut être utilisée à la place.
Notez que tout cela est spécifique à Microsoft. TCHAR n'est pas un type C++ standard, c'est une macro définie dans windows.h. wmain et _tmain sont également définis par Microsoft uniquement.
_tmain est une macro qui est redéfinie selon que vous compilez ou non avec Unicode ou ASCII. Il s’agit d’une extension de Microsoft et il n’est pas garanti qu’il fonctionne sur d’autres compilateurs.
La déclaration correcte est
int _tmain(int argc, _TCHAR *argv[])
Si la macro UNICODE est définie, cela se développe en
int wmain(int argc, wchar_t *argv[])
Sinon, il se développe pour
int main(int argc, char *argv[])
Votre définition va pour un peu de chaque, et (si vous avez défini UNICODE) sera étendu à
int wmain(int argc, char *argv[])
ce qui est tout simplement faux.
std :: cout fonctionne avec les caractères ASCII. Vous avez besoin de std :: wcout si vous utilisez des caractères larges.
essayez quelque chose comme ça
#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;
}
Ou vous pouvez simplement décider à l’avance d’utiliser des caractères larges ou étroits. :-)
Mis à jour le 12 nov 2013:
Changé le "TCHAR" traditionnel en "_TCHAR" qui semble être la dernière mode. Les deux fonctionnent bien.
Fin de mise à jour
la convention _T indique que le programme doit utiliser le jeu de caractères défini pour l'application (Unicode, ASCII, MBCS, etc.). Vous pouvez entourer vos chaînes de caractères avec _T () pour les stocker au format correct.
cout << _T( "There are " ) << argc << _T( " arguments:" ) << endl;
Ok, la question semble avoir été assez bien répondue, la surcharge UNICODE devrait prendre un tableau de caractères larges comme second paramètre. Donc, si le paramètre de ligne de commande est "Hello"
, il s’agira probablement de "H\0e\0l\0l\0o\0\0\0"
et votre programme n’imprimera que le 'H'
avant qu’il ne voie ce qu’il considère comme un terminateur nul.
Alors maintenant, vous pouvez vous demander pourquoi il compile et lie même.
Eh bien, il compile parce que vous êtes autorisé à définir une surcharge pour une fonction.
La liaison est un problème légèrement plus complexe. En C, il n’ya pas d’information de symbole décorée, il ne trouve donc que la fonction main. Les commandes argc et argv sont probablement toujours présentes en tant que paramètres de pile d'appels, même si votre fonction est définie avec cette signature, même si votre fonction les ignore.
Bien que le C++ ait des symboles décorés, il utilise presque certainement le couplage C comme principal, plutôt qu'un lieur intelligent qui les recherche à tour de rôle. Donc, il a trouvé votre wmain et mis les paramètres sur la pile d'appels au cas où il s'agisse de la version int wmain(int, wchar_t*[])
.