C++ sprintf如何使用CString和std::string

C++ sprintf如何使用CString和std::string,c++,visual-c++,visual-studio-2008,mfc,cstring,C++,Visual C++,Visual Studio 2008,Mfc,Cstring,有人能解释一下CString如何与sprintf一起正常工作吗?因为CString类的第一个元素是指向char数组的指针。实际上,CString中唯一的字段是指向字符串数组的指针。该类使用一些技巧隐藏内部数据(如字符串长度、保留缓冲区大小等),方法是分配一个大缓冲区,然后将唯一的类指针指向char数组,以获取这些内部数据字段。它将该指针移动已知偏移量 您应该做的是调用s.GetBuffer(0);或(LPCTSTR)s;但是把它当作 CString s = "test"; std::string

有人能解释一下
CString
如何与
sprintf
一起正常工作吗?

因为CString类的第一个元素是指向char数组的指针。实际上,CString中唯一的字段是指向字符串数组的指针。该类使用一些技巧隐藏内部数据(如字符串长度、保留缓冲区大小等),方法是分配一个大缓冲区,然后将唯一的类指针指向char数组,以获取这些内部数据字段。它将该指针移动已知偏移量

您应该做的是调用s.GetBuffer(0);或(LPCTSTR)s;但是把它当作

CString s = "test";
std::string ss = "test";

char z[100];
sprintf(z, "%s", ss.c_str()); // z = "test"  : OK

char z2[100];
sprintf(z2, "%s", ss); // z2 = "(null)" : OK. undefined behavior is expected

char z3[100];
sprintf(z3, "%s", s); // z3 = "test" : How is this possible ?!
是MFC创建者设计的,当然它可以在Windows下工作,在其他平台上可能会崩溃

[评论后编辑]

如果不是C样式的转换,如(LPCTSTR),您将使用C++ Case:<代码> StasyType(s);代码>。但是很快你就会发现你的代码在所有这些静态的条件下变得丑陋,特别是当你的sprintf-s有很多参数的时候。这是我记得(在我看来)的设计,C++风格的铸件是为了让你重新思考你的设计,不使用铸件。在您的情况下,应该使用std::wstringstream(假设您使用UNICODE构建),而不是使用sprintf:

#包括

std::wostream&operator微软似乎没有正式支持
CString
的这种行为(它依赖于
CString
实现细节,这些细节似乎是精心设计的,可以在您引用的情况下工作,但将来可能会改变)

请注意:

事实上,这是一个糟糕的演员阵容,因为这是一个C风格的演员阵容。我会使用C++风格的强制转换
静态强制转换(string)
或者只使用
CString::GetString()
方法

另一条是(我的重点):

在变量参数函数中使用CString对象

有些C函数的参数数量可变。著名的 例如
printf\u s
。因为这种函数是 声明时,编译器无法确定参数的类型和 无法确定要对每个对象执行的转换操作 论点因此,传递时必须使用显式类型转换 函数的
CString
对象,该函数具有可变的 参数
。要在变量参数函数中使用
CString
对象, 显式地将
CString
强制转换为
LPCTSTR
字符串,如 下面的例子

// If the prototype isn't known or is a va_arg prototype, 
// you must invoke the cast operator explicitly. For example, 
// the va_arg part of a call to swprintf_s() needs the cast:

swprintf_s(sz, 1024, L"I think that %s!\n", (PCWSTR)strSports);
同样,与MSDN文档中使用的C样式转换相比,我更喜欢C++样式的
static_cast
。或者调用
CString::GetString()
就可以了


另请参阅此博客文章:


另一个。

正确的调用方法是
CString::GetString()
,而不是
GetBuffer()
。还要注意的是,C风格的强制转换是不好的:请使用C++风格的强制转换:
static\u cast(ss)
。更准确地说,在您的情况下,强制转换应该是
static\u cast(ss)
,因为您使用的是
sprintf()
(而不是
TCHAR
这样基于
的函数。这样,在Unicode构建(自VS2005以来一直是默认的,
CString
实际上是
CStringW
)上,强制转换失败,代码无法编译,您可以修复它(而不是将错误参数传递给
sprintf()
,并在运行时无声地引入错误).
ss
是示例中的
std::string
,ITYM
s.GetBuffer(0)
等。否则将是
ss.c_str()。我不确定OP是否使用UNICODE,据我记忆所及,CString在分配给它时可以隐式地将多字节转换为wchar_t字符串。感谢您对强制转换的详细解释。
#include<sstream>

std::wostream & operator<< (std::wostream &out, CString const &s) {
  out << s.GetString();
  return out;
}

int main(){
  CString s = _T("test");
  std::wstringstream ss;
  ss << s;  // no cast required, no UB here
  std::wcout << ss.str();
  return 0;
}
// If the prototype isn't known or is a va_arg prototype, 
// you must invoke the cast operator explicitly. For example, 
// the va_arg part of a call to swprintf_s() needs the cast:

swprintf_s(sz, 1024, L"I think that %s!\n", (PCWSTR)strSports);
CString kindOfFruit = _T("bananas");
int howmany = 25;
_tprintf_s(_T("You have %d %s\n"), howmany, (LPCTSTR)kindOfFruit);