带有 %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

带有 C 函数的 std::string_view

如何修剪 std::string?

如何在带有来自 std::string 的 unordered_map 的字符串文字上使用 is_transparent 功能?

使用带有向量和向量函数的模板

什么是std::string...?怎么用?