2009-10-23 3 views
8

Nous avons besoin de passer un format _TCHAR chaîne *, et un certain nombre de char * les chaînes en fonction avec args longueur variable:Comment puis-je convertir de _TCHAR * en char * lors de l'utilisation d'arguments C++ de longueur variable?

inline void FooBar(const _TCHAR *szFmt, const char *cArgs, ...) { 
    //... 
} 

Ainsi, il peut être appelé comme ceci:

char *foo = "foo"; 
char *bar = "bar"; 
LogToFileA(_T("Test %s %s"), foo, bar); 

Évidemment, une solution simple serait d'utiliser _TCHAR au lieu de char, mais nous n'avons malheureusement pas ce luxe.

Nous devons utiliser avec va_start, etc afin que nous puissions mettre en forme une chaîne:

va_list args; 
_TCHAR szBuf[BUFFER_MED_SIZE]; 

va_start(args, cArgs); 
_vstprintf_s(szBuf, BUFFER_MED_SIZE, szFmt, args); 
va_end(args); 

Malheureusement nous ne pouvons pas utiliser parce qu'il nous donne cette erreur:

Unhandled exception at 0x6a0d7f4f (msvcr90d.dll) in foobar.exe: 
0xC0000005: Access violation reading location 0x2d86fead. 

Je pense nous devons convertir notre char * en _TCHAR * - mais comment?

+0

si vous avez le luxe d'utiliser un wchar * au lieu d'un char *, je pense que cela vous résoudre problème –

+0

Hmm, malheureusement pas - le système actuel est un méli-mélo de char * et _TCHAR * –

+0

c'est trop mauvais ... l'efficacité est-elle un problème? si non, jetez un oeil à ma réponse, cela a fonctionné pour moi –

Répondre

3

Utilisez% hs ou% hS au lieu de% s. Cela forcera les paramètres à char * comme Interpretation d'dans les deux versions ANSI et Unicode de printf() - fonctions de style, à savoir:

inline void LogToFile(const _TCHAR *szFmt, ...) 
{ 
    va_list args; 
    TCHAR szBuf[BUFFER_MED_SIZE]; 

    va_start(args, szFmt); 
    _vstprintf_s(szBuf, BUFFER_MED_SIZE, szFmt, args); 
    va_end(args); 
} 

{ 
    char *foo = "foo"; 
    char *bar = "bar"; 
    LogToFile(_T("Test %hs %hs"), foo, bar); 
} 
+0

Très bonne réponse. –

2

Habituellement, il se présente comme suit:

char *foo = "foo"; 
char *bar = "bar"; 
#ifdef UNICODE 
LogToFileW(L"Test %S %S", foo, bar); // big S 
#else 
LogToFileA("Test %s %s", foo, bar); 
#endif 

Votre question n'est pas tout à fait claire. Comment votre fonction est implémentée et comment l'utilisez-vous?

+1

Utilisez% hs ou% hS au lieu de% s et% S. Cela forcera char * dans Ansi et Unicode. Ensuite, vous pouvez supprimer la vérification pour UNICODE. –

0

c'est quelque chose que j'ai déjà utilisé pour convertir un TCHAR en char, j'espère que ça aide, même si je ne cherchais pas vraiment l'optimisation, donc ce n'est pas le moyen le plus rapide.

TCHAR tmp[255]; 
::GetWindowText(hwnd, tmp, 255); 
std::wstring s = tmp; 

//convert from wchar to char 
const wchar_t* wstr = s.c_str(); 
size_t wlen = wcslen(wstr) + 1; 
char newchar[100]; 
size_t convertedChars = 0; 
wcstombs_s(&convertedChars, newchar, wlen, wstr, _TRUNCATE); 
1

Voici ma solution était - je me réjouis de suggestions d'amélioration!

inline void FooBar(const _TCHAR *szFmt, const char *cArgs, ...) { 

    va_list args; 
    _TCHAR szBuf[BUFFER_MED_SIZE]; 

    // Count the number of arguments in the format string. 
    const _TCHAR *at = _tcschr(szFmt, '%'); 
    int argCount = 0; 
    while(at) { 
     argCount++; 
     at = _tcschr(at + 1, '%'); 
    } 

    CA2W *ca2wArr[100]; 
    LPWSTR szArgs[100]; 
    va_start(args, cArgs); 
    for (int i = 1; i < argCount + 1; i++) { 
     CA2W *ca2w = new CA2W(cArgs); 
     szArgs[i] = ca2w->m_psz; 
     ca2wArr[i] = ca2w; 
     cArgs = va_arg(args, const char *); 
    } 
    va_end(args); 

    // Use the new array we just created (skips over first element). 
    va_start(args, szArgs[0]); 
    _vstprintf_s(szBuf, BUFFER_MED_SIZE, szFmt, args); 
    va_end(args); 

    // Free up memory used by CA2W objects. 
    for (int i = 1; i < argCount + 1; i++) { 
     delete ca2wArr[i]; 
    } 

    // ... snip ... - code that uses szBuf 
} 
+0

Votre boucle pour compter les arguments n'autorise pas les littéraux "%%", et votre utilisation de va_arg() n'autorise pas les paramètres supérieurs à 32 bits. En outre, puisque _vstprintf_s() supporte déjà Ansi et Unicode, il n'est pas nécessaire de commencer par un code aussi élaboré. Y a-t-il eu un problème avec le code que je vous ai donné plus tôt? –

+0

Ah, vous avez raison à propos du comptoir. En ce qui concerne votre code, oui cela fonctionnerait bien je suppose, et nous allons l'utiliser pour le nouveau code que nous implémentons, cependant pour les usages existants (imparfaits), nous devons utiliser la fonction de hack temporaire dans ma réponse. –

Questions connexes