2009-10-23 9 views
8

Musimy zdać Format _TCHAR * łańcuch i liczbę char * ciągi do funkcji o zmiennej długości args:Jak przekonwertować z _TCHAR * na char * przy użyciu argumentów o zmiennej długości C++?

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

Tak można nazwać tak:

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

Oczywiście prostą poprawką byłoby użycie _TCHAR zamiast char, ale niestety nie mamy tego luksusu.

Musimy to wykorzystać z va_start itp więc możemy formatować ciąg:

va_list args; 
_TCHAR szBuf[BUFFER_MED_SIZE]; 

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

Niestety nie możemy korzystać z tego, ponieważ to daje nam ten błąd:

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

myślę musimy przekonwertować nasz znak * na _TCHAR * - ale jak?

+0

jeśli masz luksus użyciu WCHAR * zamiast char *, myślę, że będzie naprawić Ci problemu –

+0

Hmm, niestety nie - obecny system jest miszmasz z char * i _TCHAR * –

+0

to źle ... czy wydajność jest problemem? jeśli nie, spójrz na moją odpowiedź, zadziałało dla mnie –

Odpowiedz

3

Użyj% hs lub% hS zamiast% s. Że zmusi parametry mają być interpretowana jako char * w obu wersjach ANSI i Unicode printf() - funkcje styl, czyli:

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

Bardzo dobra odpowiedź. –

2

Zazwyczaj wygląda następująco:

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 

Twoje pytanie nie jest całkowicie jasne. Jak twoja funkcja jest zaimplementowana i jak z niej korzystasz?

+1

Użyj% hs lub% hS zamiast% si% S. To wymusi znak * zarówno w Ansi, jak i Unicode. Następnie możesz usunąć zaznaczenie dla UNICODE. –

0

to jest coś, co użyłem wcześniej, aby przekonwertować TCHAR na char, mam nadzieję, że to pomaga, chociaż tak naprawdę nie szukałem optymalizacji, więc nie jest to najszybszy sposób .. ale zadziałało!

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

Tu było moje rozwiązanie - Cieszę sugestie dotyczące poprawy!

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

Twoja pętla do zliczania argumentów nie uwzględnia literałów "%%", a użycie va_arg() nie zezwala na parametry większe niż 32-bitowe. Poza tym, ponieważ _vstprintf_s() obsługuje już zarówno Ansi, jak i Unicode, nie ma potrzeby rozpoczynania tak skomplikowanego kodu. Czy wystąpił problem z kodem, który podałem Ci wcześniej? –

+0

Ach, masz rację co do licznika. Jeśli chodzi o twój kod, tak to działałoby dobrze, zakładam, i zamierzamy użyć tego dla NOWEGO kodu, który stosujemy, jednak dla istniejących (wadliwych) zastosowań musimy użyć tymczasowej funkcji hack w mojej odpowiedzi. –

Powiązane problemy