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

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 ); 

Ответ 1

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

Первоначально он просто случайно работал с printf, но впоследствии он был сохранен как часть интерфейса класса.


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

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

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

Ответ 2

    wprintf(L"%s\n", (LPCWSTR)cstring); // Okay. It been cast to a const wchar_t*.
    wprintf(L"%s\n", cstring); // UNDEFINED BEHAVIOUR
    wprintf(L"%s\n", (LPCWSTR)s); // Okay, it a const wchar_t*.
    wprintf(L"%s\n", s); // UNDEFINED BEHAVIOUR

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

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

Ответ 3

CString имеет указатель как первый член:

class CStringA
{
      char* m_pString;
};

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

Ответ 4

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