带有 %s 和 std::string 的 sprintf 会产生乱码
Posted
技术标签:
【中文标题】带有 %s 和 std::string 的 sprintf 会产生乱码【英文标题】:sprintf with %s and std::string gives gibberish 【发布时间】:2015-07-24 10:08:59 【问题描述】:在以下代码中:
#include <string>
using namespace std;
int main()
char command[300];
string stringz = "mystringy";
sprintf(command,"echo \"something with a string %s\" ", stringz);
system(command);
return 0;
为什么是输出
something with a string 8�
而不是预期
something with a string mystringy
一个愚蠢的问题,但我找不到答案。
【问题讨论】:
【参考方案1】:printf 的 '%s' 修饰符采用 char*
,而不是 std::string
。
你可以写:
sprintf(command,"echo \"something with a string %s\" ", stringz.c_str());
这会给你一个const char*
到std::string
的内容。这显示了sprintf
的主要弱点之一——没有类型检查!
【讨论】:
谢谢,修复了常量。您对其他选项是正确的,但 c_str 是(我认为)经典。 是的,在 C++11 之前它是唯一的。顺便说一句:旧的 Microsoft MFC-CString 可以在可变参数函数期望指向 0 终止字符串的指针的地方无害地传递... @Deduplicator:无害?它不是有一个转换运算符,这被认为是一个危险的功能,这就是为什么std::string
没有它?
不,转换运算符不会起作用,传递给省略号时没有转换。事实是,唯一的成员是char*
,指向一个正确的以 0 结尾的字符串,任何额外的必要簿记数据等都被预先设置。因此它起作用了,尽管只是由于编译器和类的细节。由于 MS 同时拥有编译器和框架,因此他们有权偶尔做一些不合时宜的事情,即使这不是很好的风格。
@Deduplicator:这很有趣,我不知道。【参考方案2】:
sprintf
格式 %s
需要一个 C 字符串,这是一个以 0 结尾的 char
数组,而不是 std::string
。
【讨论】:
【参考方案3】:要添加Deduplicator
答案,请尝试添加
sprintf(command,"echo \"something with a string %s\" ", stringz.c_str());
你应该准备好了。
【讨论】:
【参考方案4】:这是因为 sprintf
期望 char *
作为参数来扩展 %s
标记。它会像
sprintf(command,"echo \"something with a string %s\" ", stringz.c_str());
它将字符串的“char *
”版本传递给sprintf
。
之所以显示那些奇怪的字符是因为整个 std::string
对象被复制到sprintf
的堆栈帧中。然后,sprintf
,它接受可变数量的参数,查看它自己的堆栈空间,并假设它将在那里找到一个char *
,但实际上是一些垃圾,是由于将字符串数据重新解释为@987654331 @,当它被取消引用时,它会导致该序列。如果运气不好,也可能出现段错误。
【讨论】:
【参考方案5】:首先你不应该使用sprintf
。这是 C++,而不是 C。std::string
以非常自然的方式支持连接,使用 +
运算符,就像在其他一些编程语言中一样:
#include <string>
int main()
std::string stringz = "mystringy";
std::string command = "echo \"something with a string " + stringz + "\" ";
system(command.c_str());
return 0;
如果您坚持使用char
-array 函数,如sprintf
,请使用stringz.c_str()
。事实上,这也是system
所要求的。但请注意我的示例如何仅在最后可能的情况下转换字符串。
【讨论】:
【参考方案6】:你可以使用:
sprintf(command,"echo \"something with a string %s\" ", stringz.c_str());
请注意,%s
采用 C 字符串,而不是 std::string
。
最好还是用,iostreams
:
string stringDemo("MYSTRING");
std::cout << stringDemo << "\n";
【讨论】:
您的建议基本上是好的,但 OP 不想写入标准输出,而只是连接字符串。std::cout
在这种情况下没有用。以上是关于带有 %s 和 std::string 的 sprintf 会产生乱码的主要内容,如果未能解决你的问题,请参考以下文章
如何在带有来自 std::string 的 unordered_map 的字符串文字上使用 is_transparent 功能?