2009-10-23 4 views
8

Tenemos que pasar una cadena de formato * _TCHAR, y una serie de char * cadenas en una función con argumentos de longitud variable:¿Cómo convierto de _TCHAR * a char * cuando utilizo args de longitud variable C++?

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

lo tanto se le puede llamar así:

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

Obviamente, una solución simple sería usar _TCHAR en lugar de char, pero desafortunadamente no tenemos ese lujo.

tenemos que utilizar esto con va_start, etc por lo que podemos dar formato a una cadena:

va_list args; 
_TCHAR szBuf[BUFFER_MED_SIZE]; 

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

Desafortunadamente, no podemos utilizar esto porque nos da este error:

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

estoy pensando necesitamos convertir nuestro char * a _TCHAR * - pero ¿cómo?

+0

si usted tiene el lujo de usar un wchar * en lugar de un char *, creo que sería arreglar el problema –

+0

Hmm, por desgracia, no - el sistema actual es una mezcla de lo char * y _TCHAR * –

+0

Eso es muy malo ... ¿es la eficiencia un problema? si no, échale un vistazo a mi respuesta, funcionó para mí –

Respuesta

3

Use% hs or% hS en lugar de% s. Que obligará a los parámetros a ser interpretado como un char * en ambas versiones ANSI y Unicode de printf() - funciones de estilo, es decir:

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

Muy buena respuesta. –

2

Por lo general, tiene el siguiente aspecto:

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 

Su pregunta no es del todo clara. ¿Cómo se implementa su función y cómo la usa?

+1

Use% hs o% hS en lugar de% s y% S. Eso forzará a char * tanto en Ansi como en Unicode. Luego puede quitar el cheque de UNICODE. –

0

esto es algo que he usado antes para convertir un TCHAR a char, espero que ayude, aunque realmente no estaba buscando la optimización, así que no es la manera más rápida ... ¡pero funcionó!

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

Aquí fue mi solución - Doy la bienvenida a sugerencias para mejorar!

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

Su bucle para contar argumentos no permite los literales "%%", y su uso de va_arg() no permite los parámetros que son mayores que 32 bits. Además, dado que _vstprintf_s() ya admite tanto Ansi como Unicode, no es necesario comenzar con un código tan elaborado. ¿Hubo algún problema con el código que te di antes? –

+0

Ah, tienes razón sobre el mostrador. En cuanto a su código, sí, esto funcionaría bien, supongo, y vamos a usar esto para el código NUEVO que implementamos, sin embargo, para usos existentes (defectuosos) debemos usar la función de corte temporal en mi respuesta. –

Cuestiones relacionadas