web-dev-qa-db-ja.com

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

CStringは、バッファクラスの文字列データを指すポインタのみが含まれるように特別に設計されています。値をprintfに渡すと、フォーマット文字列に「%s」が含まれている場合はポインタとして扱われます。

もともとはたまたまprintfで動作していましたが、後でクラスインターフェイスの一部として保持されています。


この投稿は、引退してからずっとMSのドキュメントに基づいているため、今後もこの作業を続けるという彼らの約束にリンクすることはできません。

ただし、反対票を追加する前に、私の古い知識を共有している誰かからのこのブログ投稿も読んでください。

ビッグブラザーがお手伝いします

12
Bo Persson
    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::wstringcout/wcoutに固執してください。

6
Puppy

CStringには、最初のメンバーとしてポインターがあります。

class CStringA
{
      char* m_pString;
};

char*ではありませんが(ANSI CStringの場合でも)、多かれ少なかれ同じです。 CStringオブジェクトをprintfファミリーの関数(カスタム実装がある場合はそれを含む)のいずれかに渡すと、CStringオブジェクト(スタック上にある)が渡されます。 %s解析により、ポインターであるかのように読み取られます。これは、この場合は有効なポインターです(最初のバイトのデータはm_pStringです)。

3
Ajay

一般的に言って、それは未定義の振る舞いです。 この記事 によると、Visual C++はCStringからPODタイプへの変換を呼び出して、カバーします-これは未定義の動作の許容される実装です。

2
sharptooth