2009-10-23 16 views
8

abbiamo bisogno di passare un * stringa di formato _TCHAR, e un certo numero di char * stringhe in una funzione con argomenti a lunghezza variabile:Come si converte da _TCHAR * a char * quando si usano gli argomenti di lunghezza variabile C++?

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

Così può essere definito in questo modo:

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

Ovviamente una soluzione semplice sarebbe usare _TCHAR invece di char, ma purtroppo non abbiamo quel lusso.

Abbiamo bisogno di usare questo con va_start, ecc in modo che possiamo formattare una stringa:

va_list args; 
_TCHAR szBuf[BUFFER_MED_SIZE]; 

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

Purtroppo non possiamo usare questo perché ci dà questo errore:

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

sto pensando dobbiamo convertire il nostro char * in _TCHAR * - ma come?

+0

se avete il lusso di usare un wchar * invece di un char *, penso che sarebbe risolvere si problema –

+0

Hmm, purtroppo non - il sistema attuale è un miscuglio di char * e _TCHAR * –

+0

questo è un peccato ... l'efficienza è un problema? in caso contrario, dai un'occhiata alla mia risposta, ha funzionato per me –

risposta

3

Utilizzare% hs o% hS anziché% s. Che costringerà i parametri per essere interpretato nel modo char * in entrambe le versioni ANSI e Unicode di printf() - le funzioni di stile, vale a dire:

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

Ottima risposta. –

2

Di solito appare come il seguente:

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 

tua domanda non è del tutto chiara. Come viene implementata la tua funzione e come la usi?

+1

Utilizza% hs o% hS invece di% se% s. Ciò forzerà il char * sia in Ansi che in Unicode. Quindi puoi rimuovere il controllo per UNICODE. –

0

questo è qualcosa che ho usato prima per convertire un TCHAR in char, spero che sia d'aiuto, anche se non stavo davvero cercando l'ottimizzazione, quindi non è il modo più veloce .. ma ha funzionato!

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

qui era la mia soluzione - Accolgo con favore proposte di miglioramento!

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

Il ciclo per contare gli argomenti non ammette letterali "%%" e l'utilizzo di va_arg() non consente parametri più grandi di 32 bit. Inoltre, poiché _vstprintf_s() supporta già sia Ansi che Unicode, non è necessario iniziare un codice così elaborato. C'è stato un problema con il codice che ti ho dato prima? –

+0

Ah, hai ragione sul contatore. Per quanto riguarda il tuo codice, sì, funzionerebbe bene, presumo, e useremo questo per il codice NEW che implementiamo, tuttavia per gli usi esistenti (imperfetti) dobbiamo usare la funzione di hack temporanea nella mia risposta. –

Problemi correlati