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 says(这很奇怪)
在变量参数函数中使用CString对象
将CString显式地转换为LPCTSTR字符串,如下所示:
CString kindOfFruit = "bananas";
int howmany = 25;
printf( "You have %d %s\n", howmany, (LPCTSTR)kindOfFruit );
答案 0 :(得分:12)
CString是专门设计的,它只包含一个指向缓冲区类中字符串数据的指针。当通过值传递给printf时,当在格式字符串中看到“%s”时,它将被视为指针。
它最初只是碰巧使用printf,但后来被保留为类接口的一部分。
这篇文章基于MS文档很久以来已经退休,因此我无法链接到他们将继续使其工作的承诺。
然而,在添加更多downvotes之前,请阅读分享我以前的知识的人的博客文章:
答案 1 :(得分:6)
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
。
答案 2 :(得分:3)
CString
有一个指针作为第一个成员:
class CStringA
{
char* m_pString;
};
虽然它不是char*
(即使对于ANSI CString),但它或多或少都是一样的。当您将CString对象传递给任何printf系列函数(包括您的自定义实现,如果有的话)时,您将传递CString对象(它在堆栈上)。 %s
解析导致它读取就好像它是一个指针 - 在这种情况下是一个有效的指针(第一个字节的数据是m_pString
)。
答案 3 :(得分:2)
一般来说,这是未定义的行为。根据{{3}} Visual C ++只是调用从CString
到POD类型的转换来覆盖你 - 这是允许的未定义行为的实现。