How can CString be passed to format string %s?

怎甘沉沦 提交于 2019-11-26 17:23:13

问题


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

How can CString be passed to format string %s?

By the way, MSDN says(it's weird)

To use a CString object in a variable argument function
Explicitly cast the CString to an LPCTSTR string, as shown here:

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

回答1:


CString is specifically designed such that it only contains a pointer that points to the string data in a buffer class. When passed by value to printf it will be treated as a pointer when seeing the "%s" in the format string.

It originally just happened to work with printf by chance, but this has later been kept as part of the class interface.


This post is based on MS documentation long since retired, so I cannot link to their promise that they will continue to make this work.

However, before adding more downvotes please also read this blog post from someone sharing my old knowledge:

Big Brother helps you




回答2:


    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

The only thing you can pass to this function for %s is a const wchar_t*. Anything else is undefined behaviour. Passing the CString just happens to work.

There's a reason that iostream was developed in C++, and it's because these variable-argument functions are horrifically unsafe, and shoud never be used. Oh, and CString is pretty much a sin too for plenty of reasons, stick to std::wstring and cout/wcout wherever you can.




回答3:


CString has a pointer as the first member:

class CStringA
{
      char* m_pString;
};

Though it is not char* (even for ANSI CString), it is more or less the same thing. When you pass CString object to any of printf-family of functions (including your custom implementation, if any), you are passing CString object (which is on stack). The %s parsing causes it it read as if it was a pointer - which is a valid pointer in this case (the data at very first byte is m_pString).




回答4:


Generally speaking it's undefined behavior. According to this article Visual C++ just invokes the conversion from CString to a POD type to cover you - that is permissible implementation of undefined behavior.



来源:https://stackoverflow.com/questions/6608942/how-can-cstring-be-passed-to-format-string-s

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!