【问题标题】:sprintf with %s and std::string gives gibberish带有 %s 和 std::string 的 sprintf 会产生乱码
【发布时间】: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

一个愚蠢的问题,但我找不到答案。

【问题讨论】:

    标签: c++ string printf variadic-functions stdstring


    【解决方案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 在这种情况下没有用。
            猜你喜欢
            • 2016-06-25
            • 2012-11-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-08-22
            • 2015-03-17
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多