Как можно передать CString для форматирования строки% s? - PullRequest
13 голосов
/ 07 июля 2011
class MyString
{
public:
    MyString(const std::wstring& s2)
    {
        s = s2;
    }

    operator LPCWSTR() const
    {
        return s.c_str();
    }
private:
    std::wstring s;
};

int _tmain(int argc, _TCHAR* argv[])
{
    MyString s = L"MyString";
    CStringW cstring = L"CString";
    wprintf(L"%s\n", (LPCWSTR)cstring); // Okay. Becase it has an operator LPCWSTR()
    wprintf(L"%s\n", cstring); // Okay, fine. But how?        
    wprintf(L"%s\n", (LPCWSTR)s); // Okay. fine.
    wprintf(L"%s\n", s); // Doesn't work. Why? It prints gabage string like "?."
    return 0;
}

Как передать CString в строку формата% s?

Кстати, MSDN говорит (это странно)

Чтобы использовать объект CString в функции переменного аргумента
Явно приведите CString к строке LPCTSTR, как показано здесь:

CString kindOfFruit = "bananas";
int      howmany = 25;
printf( "You have %d %s\n", howmany, (LPCTSTR)kindOfFruit ); 

Ответы [ 4 ]

12 голосов
/ 07 июля 2011

CString специально разработан таким образом, что он содержит только указатель, который указывает на строковые данные в классе буфера. При передаче по значению в printf он будет считаться указателем при отображении «% s» в строке формата.

Изначально он случайно работал с printf случайно, но позже он был сохранен как часть интерфейса класса.


Этот пост основан на документации MS, давно вышедшей на пенсию, поэтому я не могу сослаться на их обещание, что они продолжат эту работу.

Однако, прежде чем добавлять больше отрицательных голосов, пожалуйста, прочитайте эту запись в блоге от кого-то, кто делится моими старыми знаниями:

Большой брат помогает тебе

6 голосов
/ 07 июля 2011
    wprintf(L"%s\n", (LPCWSTR)cstring); // Okay. It's been cast to a const wchar_t*.
    wprintf(L"%s\n", cstring); // UNDEFINED BEHAVIOUR
    wprintf(L"%s\n", (LPCWSTR)s); // Okay, it's a const wchar_t*.
    wprintf(L"%s\n", s); // UNDEFINED BEHAVIOUR

То, что * можно передать этой функции для %s, это const wchar_t*. Все остальное - неопределенное поведение. Передача CString просто работает.

Есть причина, по которой iostream был разработан в C ++, и это потому, что эти функции с переменными аргументами ужасно небезопасны и никогда не должны использоваться. Да, и CString также является грехом по многим причинам, придерживайтесь std::wstring и cout / wcout, где вы можете.

3 голосов
/ 14 июля 2011

CString имеет указатель в качестве первого члена:

class CStringA
{
      char* m_pString;
};

Хотя это не char* (даже для ANSI CString), это более или менее то же самое.Когда вы передаете объект CString какой-либо функции семейства printf (включая вашу пользовательскую реализацию, если есть), вы передаете объект CString (который находится в стеке).Синтаксический анализ %s приводит к тому, что он читается так, как если бы он был указателем - который в данном случае является действительным указателем (данные в самом первом байте m_pString).

2 голосов
/ 07 июля 2011

Вообще говоря, это неопределенное поведение.Согласно этой статье Visual C ++ просто вызывает преобразование из CString в тип POD, чтобы охватить вас - это допустимая реализация неопределенного поведения.

...