我的理解是,字符串是std名称空间的成员,那么为什么会发生以下情况?

#include <iostream>

int main()
{
    using namespace std;

    string myString = "Press ENTER to quit program!";
    cout << "Come up and C++ me some time." << endl;
    printf("Follow this command: %s", myString);
    cin.get();

    return 0;
}

每次程序运行时,myString输出一个看似随机的3个字符的字符串,如上面的输出。


当前回答

它是编译的,因为printf不是类型安全的,因为它使用C意义上的变量参数。printf没有std::string选项,只有c风格的字符串。使用其他东西来代替它所期望的东西肯定不会给你想要的结果。这实际上是一种未定义的行为,所以任何事情都可能发生。

修复这个问题最简单的方法,因为你使用的是c++,通常用std::cout打印它,因为std::string通过操作符重载支持它:

std::cout << "Follow this command: " << myString;

如果出于某种原因,你需要提取c风格的字符串,你可以使用std::string的c_str()方法来获得一个以null结尾的const char *。举个例子:

#include <iostream>
#include <string>
#include <stdio.h>

int main()
{
    using namespace std;

    string myString = "Press ENTER to quit program!";
    cout << "Come up and C++ me some time." << endl;
    printf("Follow this command: %s", myString.c_str()); //note the use of c_str
    cin.get();

    return 0;
}

如果你想要一个类似printf,但类型安全的函数,查看可变参数模板(c++ 11,在MSVC12之前的所有主要编译器上都支持)。你可以在这里找到一个例子。据我所知,在标准库中还没有这样的实现,但在Boost中可能会有,特别是Boost::format。


[1]:这意味着您可以传递任意数量的参数,但函数依赖于您告诉它这些参数的数量和类型。在printf的情况下,这意味着包含编码类型信息的字符串,例如%d表示int。如果你在类型或数字上撒谎,函数没有标准的方法来知道,尽管一些编译器有能力在你撒谎时检查并给出警告。

其他回答

如果你想要一个类似c的字符串(const char*)用于printf,请使用myString.c_str()

谢谢

主要原因可能是c++字符串是一个包含当前长度值的结构体,而不仅仅是以0字节结束的字符序列的地址。Printf及其相关函数希望找到这样的序列,而不是结构体,因此会被c++字符串弄糊涂。

就我个人而言,我相信printf有一个c++语法特性无法轻易填充的地方,就像html中的表结构有一个div无法轻易填充的地方一样。就像Dykstra后来写的goto一样,他并不打算开始一种宗教,实际上只是反对把它作为一个拼凑品来弥补设计糟糕的代码。

如果GNU项目能将printf家族添加到他们的g++扩展中,那就太好了。

它是编译的,因为printf不是类型安全的,因为它使用C意义上的变量参数。printf没有std::string选项,只有c风格的字符串。使用其他东西来代替它所期望的东西肯定不会给你想要的结果。这实际上是一种未定义的行为,所以任何事情都可能发生。

修复这个问题最简单的方法,因为你使用的是c++,通常用std::cout打印它,因为std::string通过操作符重载支持它:

std::cout << "Follow this command: " << myString;

如果出于某种原因,你需要提取c风格的字符串,你可以使用std::string的c_str()方法来获得一个以null结尾的const char *。举个例子:

#include <iostream>
#include <string>
#include <stdio.h>

int main()
{
    using namespace std;

    string myString = "Press ENTER to quit program!";
    cout << "Come up and C++ me some time." << endl;
    printf("Follow this command: %s", myString.c_str()); //note the use of c_str
    cin.get();

    return 0;
}

如果你想要一个类似printf,但类型安全的函数,查看可变参数模板(c++ 11,在MSVC12之前的所有主要编译器上都支持)。你可以在这里找到一个例子。据我所知,在标准库中还没有这样的实现,但在Boost中可能会有,特别是Boost::format。


[1]:这意味着您可以传递任意数量的参数,但函数依赖于您告诉它这些参数的数量和类型。在printf的情况下,这意味着包含编码类型信息的字符串,例如%d表示int。如果你在类型或数字上撒谎,函数没有标准的方法来知道,尽管一些编译器有能力在你撒谎时检查并给出警告。

您可以使用snprinft来确定所需的字符数量,并分配适当大小的缓冲区。

int length = std::snprintf(nullptr, 0, "There can only be %i\n", 1 );
char* str = new char[length+1]; // one more character for null terminator
std::snprintf( str, length + 1, "There can only be %i\n", 1 );
std::string cppstr( str );
delete[] str;

这是对cppreference.com上一个例子的一个小的改编

使用std::printf和c_str() 例子:

std::printf("Follow this command: %s", myString.c_str());