C++ printf 与 std::string?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10865957/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
printf with std::string?
提问by TheDarkIn1978
My understanding is that string
is a member of the std
namespace, so why does the following occur?
我的理解是它string
是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;
}
Each time the program runs, myString
prints a seemingly random string of 3 characters, such as in the output above.
每次程序运行时,myString
打印一个看似随机的 3 个字符的字符串,如上面的输出。
回答by chris
It's compiling because printf
isn't type safe, since it uses variable arguments in the C sense1. printf
has no option for std::string
, only a C-style string. Using something else in place of what it expects definitely won't give you the results you want. It's actually undefined behaviour, so anything at all could happen.
它正在编译,因为printf
它不是类型安全的,因为它使用 C 意义上的变量参数1。printf
没有选项std::string
,只有一个 C 风格的字符串。使用其他东西代替它所期望的肯定不会给你想要的结果。这实际上是未定义的行为,所以任何事情都可能发生。
The easiest way to fix this, since you're using C++, is printing it normally with std::cout
, since std::string
supports that through operator overloading:
解决此问题的最简单方法,因为您使用的是 C++,所以通常使用 打印它std::cout
,因为std::string
通过运算符重载支持它:
std::cout << "Follow this command: " << myString;
If, for some reason, you need to extract the C-style string, you can use the c_str()
method of std::string
to get a const char *
that is null-terminated. Using your example:
如果由于某种原因需要提取 C 样式字符串,则可以使用 的c_str()
方法std::string
来获取以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;
}
If you want a function that is like printf
, but type safe, look into variadic templates (C++11, supported on all major compilers as of MSVC12). You can find an example of one here. There's nothing I know of implemented like that in the standard library, but there might be in Boost, specifically boost::format
.
如果您想要一个类似于printf
,但类型安全的函数,请查看可变参数模板(C++11,自 MSVC12 起,所有主要编译器都支持)。你可以在这里找到一个例子。我不知道在标准库中实现了什么,但在 Boost 中可能有,特别是boost::format
.
[1]: This means that you can pass any number of arguments, but the function relies on you to tell it the number and types of those arguments. In the case of printf
, that means a string with encoded type information like %d
meaning int
. If you lie about the type or number, the function has no standard way of knowing, although some compilers have the ability to check and give warnings when you lie.
[1]:这意味着您可以传递任意数量的参数,但该函数依赖于您告诉它这些参数的数量和类型。在 的情况下printf
,这意味着具有编码类型信息的字符串,如%d
含义int
。如果你在类型或数字上撒谎,函数没有标准的知道方式,尽管一些编译器有能力在你撒谎时检查并给出警告。
回答by Jerry Coffin
Please don't use printf("%s", your_string.c_str());
请不要使用 printf("%s", your_string.c_str());
Use cout << your_string;
instead. Short, simple and typesafe. In fact, when you're writing C++, you generally want to avoid printf
entirely -- it's a leftover from C that's rarely needed or useful in C++.
使用cout << your_string;
来代替。简短、简单且类型安全。事实上,当您编写 C++ 时,您通常希望printf
完全避免——它是 C 的剩余部分,在 C++ 中很少需要或有用。
As to whyyou should use cout
instead of printf
, the reasons are numerous. Here's a sampling of a few of the most obvious:
至于为什么应该使用cout
而不是printf
,原因有很多。以下是一些最明显的示例:
- As the question shows,
printf
isn't type-safe. If the type you pass differs from that given in the conversion specifier,printf
will try to use whatever it finds on the stack as if it were the specified type, giving undefined behavior. Some compilers can warn about this under some circumstances, but some compilers can't/won't at all, and none can under all circumstances. printf
isn't extensible. You can only pass primitive types to it. The set of conversion specifiers it understands is hard-coded in its implementation, and there's no way for you to add more/others. Most well-written C++ should use these types primarily to implement types oriented toward the problem being solved.It makes decent formatting much more difficult. For an obvious example, when you're printing numbers for people to read, you typically want to insert thousands separators every few digits. The exact number of digits and the characters used as separators varies, but
cout
has that covered as well. For example:std::locale loc(""); std::cout.imbue(loc); std::cout << 123456.78;
The nameless locale (the "") picks a locale based on the user's configuration. Therefore, on my machine (configured for US English) this prints out as
123,456.78
. For somebody who has their computer configured for (say) Germany, it would print out something like123.456,78
. For somebody with it configured for India, it would print out as1,23,456.78
(and of course there are many others). Withprintf
I get exactly one result:123456.78
. It is consistent, but it's consistently wrongfor everybody everywhere. Essentially the only way to work around it is to do the formatting separately, then pass the result as a string toprintf
, becauseprintf
itself simply will notdo the job correctly.- Although they're quite compact,
printf
format strings can be quite unreadable. Even among C programmers who useprintf
virtually every day, I'd guess at least 99% would need to look things up to be sure what the#
in%#x
means, and how that differs from what the#
in%#f
means (and yes, they mean entirely different things).
- 正如问题所示,
printf
不是类型安全的。如果您传递的类型与转换说明符中给出的类型不同,printf
将尝试使用它在堆栈中找到的任何内容,就好像它是指定的类型一样,给出未定义的行为。有些编译器在某些情况下可以警告这一点,但有些编译器不能/不会,在所有情况下都不能。 printf
不可扩展。您只能将原始类型传递给它。它理解的一组转换说明符在其实现中是硬编码的,您无法添加更多/其他。大多数编写良好的 C++ 应该主要使用这些类型来实现面向要解决的问题的类型。它使体面的格式化变得更加困难。举一个明显的例子,当您打印数字供人们阅读时,您通常希望每隔几位插入千位分隔符。数字的确切数量和用作分隔符的字符各不相同,但
cout
也涵盖了这一点。例如:std::locale loc(""); std::cout.imbue(loc); std::cout << 123456.78;
无名语言环境(“”)根据用户的配置选择语言环境。因此,在我的机器(配置为美国英语)上,它打印为
123,456.78
. 对于将计算机配置为(例如)德国的人来说,它会打印出类似123.456,78
. 对于为印度配置了它的人,它会打印为1,23,456.78
(当然还有很多其他的)。随着printf
我得到完全一个结果:123456.78
。它是一致的,但对任何地方的每个人来说都是错误的。基本上解决它的唯一方法是单独进行格式化,然后将结果作为字符串传递给printf
,因为printf
它本身根本无法正确完成工作。- 尽管它们非常紧凑,但
printf
格式字符串可能非常不可读。即使在printf
几乎每天都使用的 C 程序员中,我想至少有 99% 的人需要查找东西来确定#
in 的%#x
含义,以及这与#
in 的%#f
含义有何不同(是的,它们的含义完全不同) )。
回答by Alessandro Pezzato
use myString.c_str()
if you want a c-like string (const char*
) to use with printf
使用myString.c_str()
,如果你想有一个类似C的字符串(const char*
)与printf的使用
thanks
谢谢
回答by Adel Ben Hamadi
Use std::printfand c_str() example:
使用std::printf和 c_str() 示例:
std::printf("Follow this command: %s", myString.c_str());
回答by howard howard
Printf is actually pretty good to use if size matters. Meaning if you are running a program where memory is an issue, then printf is actually a very good and under rater solution. Cout essentially shifts bits over to make room for the string, while printf just takes in some sort of parameters and prints it to the screen. If you were to compile a simple hello world program, printf would be able to compile it in less than 60, 000 bits as opposed to cout, it would take over 1 million bits to compile.
如果大小很重要,Printf 实际上非常好用。意思是,如果您正在运行一个内存有问题的程序,那么 printf 实际上是一个非常好的评估器解决方案。Cout 本质上是移动位来为字符串腾出空间,而 printf 只是接收某种参数并将其打印到屏幕上。如果您要编译一个简单的 hello world 程序, printf 将能够以少于 60, 000 位的方式编译它,而 cout 则需要超过 100 万位才能编译。
For your situation, id suggest using cout simply because it is much more convenient to use. Although, I would argue that printf is something good to know.
对于您的情况,id 建议使用 cout 只是因为它使用起来方便得多。虽然,我认为 printf 是值得知道的。
回答by Hyena
printf
accepts a variable number of arguments. Those can only have Plain Old Data (POD) types. Code that passes anything other than POD to printf
only compiles because the compiler assumes you got your format right. %s
means that the respective argument is supposed to be a pointer to a char
. In your case it is an std::string
not const char*
. printf
does not know it because the argument type goes lost and is supposed to be restored from the format parameter. When turning that std::string
argument into const char*
the resulting pointer will point to some irrelevant region of memory instead of your desired C string. For that reason your code prints out gibberish.
printf
接受可变数量的参数。那些只能具有普通旧数据 (POD) 类型。传递 POD 以外的任何内容的代码printf
只会编译,因为编译器假定您的格式正确。%s
意味着相应的参数应该是指向 a 的指针char
。在您的情况下,它std::string
不是const char*
。printf
不知道,因为参数类型丢失了,应该从格式参数中恢复。当将该std::string
参数转换const char*
为结果指针时,将指向一些不相关的内存区域,而不是您想要的 C 字符串。因此,您的代码会打印出乱码。
While printf
is an excellent choice for printing out formatted text, (especially if you intend to have padding), it can be dangerous if you haven't enabled compiler warnings. Always enable warningsbecause then mistakes like this are easily avoidable. There is no reason to use the clumsy std::cout
mechanism if the printf
family can do the same task in a much faster and prettier way. Just make sure you have enabled all warnings (-Wall -Wextra
) and you will be good. In case you use your own custom printf
implementation you should declare it with the __attribute__
mechanism that enables the compiler to check the format string against the parameters provided.
虽然printf
是打印格式化文本的绝佳选择(特别是如果您打算使用填充),但如果您尚未启用编译器警告,则可能会很危险。始终启用警告,因为这样的错误很容易避免。std::cout
如果printf
家庭能够以更快、更漂亮的方式完成相同的任务,就没有理由使用笨拙的机制。只要确保您已启用所有警告 ( -Wall -Wextra
) 就可以了。如果您使用自己的自定义printf
实现,则应使用使编译器能够根据提供的参数检查格式字符串的__attribute__
机制来声明它。
回答by MMacD
The main reason is probably that a C++ string is a struct that includes a current-length value, not just the address of a sequence of chars terminated by a 0 byte. Printf and its relatives expect to find such a sequence, not a struct, and therefore get confused by C++ strings.
主要原因可能是 C++ 字符串是一个包含当前长度值的结构,而不仅仅是以 0 字节结尾的字符序列的地址。Printf 及其亲属希望找到这样的序列,而不是结构体,因此会被 C++ 字符串混淆。
Speaking for myself, I believe that printf has a place that can't easily be filled by C++ syntactic features, just as table structures in html have a place that can't easily be filled by divs. As Dykstra wrote later about the goto, he didn't intend to start a religion and was really only arguing against using it as a kludge to make up for poorly-designed code.
就我个人而言,我认为 printf 有一个地方不能被 C++ 的语法特性轻易填充,就像 html 中的表结构有一个不能被 div 轻易填充的地方一样。正如 Dykstra 后来写到的关于 goto 的文章,他并不打算创立一种宗教,而且实际上只是反对将其用作弥补设计不佳代码的杂物。
It would be quite nice if the GNU project would add the printf family to their g++ extensions.
如果 GNU 项目将 printf 系列添加到他们的 g++ 扩展中,那就太好了。