std::string s("foo");
sprintf(buf,"%s",s);
为什么至少在MSVC 2010下这行代码在DEBUG中没有错误,但在RELEASE中有错误?
答案 0 :(得分:9)
%s
格式说明符期望NULL终止char*
。您正在传递std::string
个实例。如果它在DEBUG中有效,那只是纯粹的运气。
您应该使用:
std::string s("foo");
sprintf(buf, "%s", s.c_str());
这将提取char*
并确保缓冲区以NULL结尾。
在运行时库std::string
中可能有不同的DEBUG和RELEASE实现。尝试使用这两种设置进行编译,但是将调试符号添加到RELEASE构建中,然后逐步执行代码。查看存储s
的内存位置。有什么不同吗?
答案 1 :(得分:4)
像sprintf()
这样的变量函数不是严格类型安全的,因为任何参数类型都被接受(在编译时)作为可变参数集的一部分。
正如其他答案所示,"%s"
是一个格式说明符,需要NULL
终止的字符串。在这种情况下传递std :: string可能是未定义的。
如果它在DEBUG模式下工作,它可能只是“幸运”,因为实现恰好打印了正确的结果(可能源于std :: string对象的c样式转换为字符指针)。 / p>
答案 2 :(得分:3)
那应该不行。你可能会遇到未定义的行为。
std::string s("foo");
sprintf(buf,"%s",s.c_str());
您实际上可能正在使用流。
答案 3 :(得分:2)
那是错的。你应该这样写:
std::string s("foo");
sprintf(buf,"%s",s.c_str());
std::string
类型的对象无法传递给sprintf
,因为没有格式说明符对应std::string
。此外,%s
期望对象类型为char*
或char[]
,c_str()
函数返回char*
,因此上述方法可行。
答案 4 :(得分:0)
如果你打算混淆c和c ++然后(出于性能原因,基于你给出的评论),那么最好将函数包装在c ++中以避免这些微妙的错误。
struct console_out
{
static void
print(const string& s)
{
sprintf(buf, "%s", s.c_str());
}
//other overloads should you want them
}
小心一次,然后让编译器小心。
我有时候认为这样的错误在c和c ++中太容易了,但我们可以搞砸了。