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 ?!
有人可以解释CString
与sprintf
的合作方式吗?
答案 0 :(得分:7)
它的工作原理是因为CString类的第一个元素是一个指向char数组的指针。实际上,CString中唯一的字段是指向字符串数组的指针。这个类使用一些技巧来隐藏内部数据(如字符串长度,保留缓冲区大小等),方法是分配一个大缓冲区,然后将唯一的类指针指向char数组,以获取那些内部数据字段,它通过已知的方式移动此指针偏移量。
你应该做的是调用s.GetBuffer(0);或(LPCTSTR)s;但用它作为
sprintf(z2, "%s", ss);
被允许作为MFC创建者的设计,当然它可以在Windows下在其他可能崩溃的平台上运行。
[评论后编辑]
如果不使用像(LPCTSTR)s
这样的c样式转换,你的代码会更安全,你将使用c ++ cast:static_cast<LPCTSTR>(s);
。但是很快你就会发现你的代码在所有这些static_cast-s中都很难看,特别是如果你的sprintf-s有很多参数的话。这是我记忆(在我看来)的设计,c ++风格的演员表旨在让你重新考虑你的设计,根本不使用演员表。在你的情况下,你应该使用std :: wstringstream而不是使用sprintf(假设你使用UNICODE构建):
#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;
}
答案 1 :(得分:6)
CString
的这种行为似乎不正式支持Microsoft(它依赖于CString
的实施细节,它们似乎可以在像你引用的那个案例,但将来可能会改变。)
请注意MSDN documentation of CString
PCXSTR
cast operator读取:
// 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);
实际上演员阵容很糟糕,因为它是一个C风格的演员阵容。我会使用C ++风格的强化 static_cast<PCWSTR>(string)
或仅使用 CString::GetString()
方法。
另一个MSDN documentation page读取(强调我的):
在变量参数函数中使用CString对象
某些C函数采用可变数量的参数。值得注意的 示例是
printf_s
。因为这种功能的方式 声明,编译器无法确定参数的类型和 无法确定要对每个操作执行哪个转换操作 论点。因此,传递时必须使用显式类型转换 函数的CString
对象,其中是变量的 参数 即可。要在变量参数函数中使用CString
对象, 显式地将CString
强制转换为LPCTSTR
字符串,如图所示 以下示例。CString kindOfFruit = _T("bananas"); int howmany = 25; _tprintf_s(_T("You have %d %s\n"), howmany, (LPCTSTR)kindOfFruit);
同样,我更喜欢 C ++ - 样式 static_cast<PCTSTR>
到MSDN文档中使用的C样式转换。或者致电CString::GetString()
会很好。
另请参阅此博文:Big Brother helps you。
另一个thread on StackOverflow in which this issue is discussed。