4 Answers
4

When you use the %s specifier with printf() you promise to pass a char const* as the corresponding argument. Passing anything except a char const* or something which decays into a char const* is undefined behavior. Certainly, passing a C++ object will have undefined behavior.

The proper way to pass a std::string to printf() is to use the %s format specifier and use the c_str() member, e.g.:

printf("string=%s\n", s.c_str());

You are using %d as a format specifier for std::string::size_type. That will probably work but it isn't guaranteed to work! Although std::string::size_type is guaranteed to be std::size_t, this type may be unsigned int, unsigned long, unsigned long long, or even some non-standard built-in integral type! The proper way to spell the format specifier for std::size_t is %zu (and certainly not %ul as in another post: it was probably meant to be %lu which is, however, still wrong:

printf("string.size()=%zu\n", s.size());

Since you are using C++, you are probably better off having the compiler figure out what formatting to call:

The program has undefined behaviour because function printf is unable to output objects of type std::string. When format symbol %s is used the function supposes that the corresponding argument is a pointer of a string literal. So the function tries to output the object of type std::string as a string literal.
To use correctly function printf with objects of type std::string you should convert them to strings using member function c_str() or data() (for C++ 2011). For example

Not that %ul is not a format specifier for unsigned long although it is the literal suffix: %ul is %u for an unsigned int followed by an l character. You probably meant to write %lu which is, however, still wrong: the correct format specifier for std::size_t is %zu.
–
Dietmar KühlJan 8 '14 at 22:38

@Dietmar Kühl, I think you are wrong. From the C Standard l (ell) Specifies that a following d, i, o, u, x, or X conversion specifier applies to a long int or unsigned long int...
–
Vlad from MoscowJan 8 '14 at 22:45

@Dietmar Kühl Or did you mean that should be used %lu? As for size_t then thanks. I could not remember the specifier at that moment when I was writing the post.
–
Vlad from MoscowJan 8 '14 at 22:48

size_t's size is not specified and it isn't guaranteed that it is of type unsigned long. For size_t the proper length modifier is z (see 7.21.6.1 paragraph 7, sixth item: "z Specifies that a following d, i, o, u, x, or X conversion specifier applies to a size_t or the corresponding signed integer type argument; ..."). ... and the length modifier precedes the conversion specifier, i.e., %zu for size_t and %lu for unsigned long.
–
Dietmar KühlJan 8 '14 at 23:01

itoa() is not standard in C++. There is std::stoi() though, so let's use that instead. We could also use std::snprintf if we are writing to a character array, and not a std::string.

If we're going to use printf() with a std::string, we will need to use the std::string::c_str() method to return a character array and print that instead. printf itself doesn't understand C++ objects. (We could also use cout, which does understand c++ objects).

As stated before, %lu is the wrong format specifier: there is no guarantee that std::size_t is a typedef for unsigned long. The correct format specifier is %zu. Conveniently, that clearly states that C's format specifiers are really hard to use, making it is clear that using IOStreams is safer.
–
Dietmar KühlJan 9 '14 at 0:23

As another answer pointed out, the reason for the (null) value is because the (formal) printf%s expects a const char* for its input, a std::string is not a const char* and results in undefined behavior... The reason for the random number when you do your first theString.length() has to do with your compiler.

On OpenBSD 5.1 with g++ 4.2.1, when I compile the code I get numerous warnings; one in particular is use of itoa, I had to change to sprintf, I also get the following warning about %s with printf on a std::string: warning: cannot pass objects of non-POD type 'struct std::string' through '...'; call will abort at runtime.

When I run the compiled code it aborts and core dumps at the first printf because of the call to %s on a std::string 'object' (which is the 'correct' behavior though technically still 'undefined behavior')

However, when I compile the above code (without edits) on an MS compiler, I actually get the following output:

string is: 997799 of length 6
buffer is: 997799 of length 6

Which is still 'undefined' but the 'expected' results.

So apparently the MS compiler recognizes the std::string on a printf and 'changes' it to a string.c_str() call OR the printf in the MS C/C++ library accepts a std::string and calls the .c_str() for you.

So to be 100% 'compatible' and C++ 'compliant' consider the following: