I have the following code:
char szBuf[256] = "";
std::string szFmt = "You have recieved %s item."
string szName = "Fork";
snprintf(szBuf, sizeof(szBuf), szFmt.c_str(), szName);
I'm trying to combine szFmt with szBuf while combining szFmt with szName according to.However, when I execute this code in win10, I getting such an weird output:
You've received the LÃý item.
And when I try to execute the code in OSX El Capitan, I'm getting the following error
cannot pass object of non-trivial type 'string' throgh variadic function;
call will about at runtime
So what is the problem, and how can I solve this?
Note: I checked this question, but in the answer, they are passing directly "Fork", which also works in me; however it doesn't work when I pass it as szName.
Better solutions were mentioned in the comments (ostringstream) but for further educational value, I'll address the immediate problem here.
Varargs (the mechanism through which the printf family of functions can accept a variable number of arguments) are not as strictly type checked as the rest. In this case, snprintf is expecting a char* to the string, but you're passing szName which is a string object. So you need to call .c_str() on that as well:
snprintf(szBuf, sizeof(szBuf), szFmt.c_str(), szName.c_str());
Using std::ostringstream will simplify things, especially since it's more type-safe than the printf functions inherited from C, but also since it can handle all standard types and with proper overloading of the output operator << you can also use it very easily for custom classes.
The important thing to remember with std::ostringstream is that it is an ordinary output stream, just like std::cout, and if you can use std::cout then you can also use std::ostringstream (or any other standard output stream).
Now for how to use it:
std::ostringstream ostr; // Define the stream object
ostr << "You have recieved " << szName << " item.";
And that's about it.
To access the string you use the str function:
std::cout << "The output is " << ostr.str() << '\n';
And if you want to copy it into a char buffer for some reason:
// Use `strncpy` to not overflow the destination buffer
std::strncpy(szBuf, ostr.str().c_str(), sizeof szBuf - 1);
// Remember that `strncpy` might not terminate the destination, so do it explicitly
szBuf[sizeof szBuf - 1] = '\0';
Related
This question already has answers here:
How to construct a std::string with embedded values, i.e. "string interpolation"?
(8 answers)
Closed 2 years ago.
I am currently learning C++ and I cannot find how to create a string with a formatter to take multiple parameters such as using sprintf but for an unknown string length.
What I want do is something like
string myString = string.format("Hello, here is %s %s and another %s", par1, par2, par3);
I know in C there is the asprintf function where it works out how long the string will be and it malloc's the memory and you need to free it when finished, however, this doesn't seem to be available for C++, although sprintf is. Everything I've seen on google about asprintf seems to mostly focus on Linux, whereas I need cross platform.
Everything I've seen about C++ and string formatting you need to define a char array of fixed length and use sprintf, but I am not going to know the length of the string so I can't do this.
In addition to the existing excellent answer, you may consider the Boost Format library.
Example:
std::string myString = str(boost::format("Hello, here is %s %s an another %s") % par1 % par2 % par3);
Get the book The Standard C++ Library by Josuttis. It will give you the complete string interface and much, much more. You appear to be thinking C, not C++. You could of course use a C interface like sprintf() to load a
char[] and then copy that to a C++ string. That is usually a bad idea.
Two ways to do what you ask:
string myString("Hello, here is ");
myString += par1;
myString += " ";
myString += par2;
myString += " and another ";
myString += par3;
stringstream foo;
foo << "Hello, here is " << par1 << " " << par2 << " and another " << par3;
string myString(foo.str());
There are lots of answers.
As C++ strings get very long, you want to use the std::stringstream to build them. This allows you to write to a string as though it were a file in memory, and it is written to handle very large strings efficiently. The C function snprintf() returns the number of characters it would have written if passed a null pointer. So you need to call it twice, once to get the size, then allocate the buffer and call again to format. It's a good solution for strings which are expected to be quite short and with a defined format, but might get arbitrarily long, like a string containing someone's name.
Note that printf() formats are convenient and easy to use for basic output of integers, string, and reals, but they don't scale up to user-defined objects because there's no accepted way of writing a toString() method and destroying the string after the call. They also can't handle arrays of objects. There is an accepted convention that overloading << writes a text representation of an object to a stream.
I am using sprintf function in C++ 11, in the following way:
std::string toString()
{
std::string output;
uint32_t strSize=512;
do
{
output.reserve(strSize);
int ret = sprintf(output.c_str(), "Type=%u Version=%u ContentType=%u contentFormatVersion=%u magic=%04x Seg=%u",
INDEX_RECORD_TYPE_SERIALIZATION_HEADER,
FORAMT_VERSION,
contentType,
contentFormatVersion,
magic,
segmentId);
strSize *= 2;
} while (ret < 0);
return output;
}
Is there a better way to do this, than to check every time if the reserved space was enough? For future possibility of adding more things.
Your construct -- writing into the buffer received from c_str() -- is undefined behaviour, even if you checked the string's capacity beforehand. (The return value is a pointer to const char, and the function itself marked const, for a reason.)
Don't mix C and C++, especially not for writing into internal object representation. (That is breaking very basic OOP.) Use C++, for type safety and not running into conversion specifier / parameter mismatches, if for nothing else.
std::ostringstream s;
s << "Type=" << INDEX_RECORD_TYPE_SERIALIZATION_HEADER
<< " Version=" << FORMAT_VERSION
// ...and so on...
;
std::string output = s.str();
Alternative:
std::string output = "Type=" + std::to_string( INDEX_RECORD_TYPE_SERIALIZATION_HEADER )
+ " Version=" + std::to_string( FORMAT_VERSION )
// ...and so on...
;
The C++ patterns shown in other answers are nicer, but for completeness, here is a correct way with sprintf:
auto format = "your %x format %d string %s";
auto size = std::snprintf(nullptr, 0, format /* Arguments go here*/);
std::string output(size + 1, '\0');
std::sprintf(&output[0], format, /* Arguments go here*/);
Pay attention to
You must resize your string. reserve does not change the size of the buffer. In my example, I construct correctly sized string directly.
c_str() returns a const char*. You may not pass it to sprintf.
std::string buffer was not guaranteed to be contiguous prior to C++11 and this relies on that guarantee. If you need to support exotic pre-C++11 conforming platforms that use rope implementation for std::string, then you're probably better off sprinting into std::vector<char> first and then copying the vector to the string.
This only works if the arguments are not modified between the size calculation and formatting; use either local copies of variables or thread synchronisation primitives for multi-threaded code.
We can mix code from here https://stackoverflow.com/a/36909699/2667451 and here https://stackoverflow.com/a/7257307 and result will be like that:
template <typename ...Args>
std::string stringWithFormat(const std::string& format, Args && ...args)
{
auto size = std::snprintf(nullptr, 0, format.c_str(), std::forward<Args>(args)...);
std::string output(size + 1, '\0');
std::sprintf(&output[0], format.c_str(), std::forward<Args>(args)...);
return output;
}
A better way is to use the {fmt} library. Ex:
std::string message = fmt::sprintf("The answer is %d", 42);
It exposes also a nicer interface than iostreams and printf. Ex:
std::string message = fmt::format("The answer is {}", 42);`
See:
https://github.com/fmtlib/fmt
http://fmtlib.net/latest/api.html#printf-formatting-functions
Your code is wrong. reserve allocates memory for the string, but does not change its size. Writing into the buffer returned by c_str does not change its size either. So the string still believes its size is 0, and you've just written something into the unused space in the string's buffer. (Probably. Technically, the code has Undefined Behaviour, because writing into c_str is undefined, so anything could happen).
What you really want to do is forget sprintf and similar C-style functions, and use the C++ way of string formatting—string streams:
std::ostringstream ss;
ss << "Type=" << INDEX_RECORD_TYPE_SERIALIZATION_HEADER
<< " Version=" << FORAMT_VERSION
<< /* ... the rest ... */;
return ss.str();
Yes, there is!
In C, the better way is to associate a file with the null device and make a dummy printf of the desired output to it, to learn how much space would it take if actually printed. Then allocate appropriate buffer and sprintf the same data to it.
In C++ you could associate the output stream with a null device, too, and test the number of charactes printed with std::ostream::tellp. However, using ostringstream is a way better solution – see the answers by DevSolar or Angew.
You can use an implementation of sprintf() into a std::string I wrote that uses vsnprintf() under the hood.
It splits the format string into sections of plain text which are just copied to the destination std::string and sections of format fields (such as %5.2lf) which are first vsnprintf()ed into a buffer and then appended to the destination.
https://gitlab.com/eltomito/bodacious-sprintf
I followed this tutorial (http://codebase.eu/tutorial/linux-socket-programming-c/) and made a server. The thing is that when the server receives a string from the client, I don't know how to compare it. For example, the following doesn't work:
bytes_received = recv(new_sd, incomming_data_buffer, 1000, 0);
if(bytes_received == 0)
cout << "host shut down." << endl;
if(bytes_received == -1)
cout << "receive error!" << endl;
incomming_data_buffer[bytes_received] = '\0';
cout << "Received data: " << incomming_data_buffer << endl;
//The comparison in the if below doesn't work. The if isn't entered
//if the client sent "Hi", which should work
if(incomming_data_buffer == "Hi\n")
{
cout << "It said Hi!" << endl;
}
You are attempting to compare a character pointer with a string literal (which will resolve to a character pointer), so yeah, the code you have definitely won't work (nor should it). Since your in C++, I would suggest this:
if(std::string(incomming_data_buffer) == "Hi\n")
cout<<"It said Hi!"<<endl;
Now, you need to include string for this work, but I assume you are already doing this, especially if you are comparing strings using this method other places in your code.
Just an explanation of what's going on here, since you appear to be relatively new to C++. In C, string literals are stored as const char*, and mutable strings are simply character arrays. If you've ever programmed C, you might remember that (char* == char*) doesn't actually compare strings, you would need the strcmp() function for that.
C++, however, introduces the std::string type, which can be directly compared using the '==' operator (and concatenated using the '+' operator). But, C code still runs in C++, so char* arrays are not necessarily promoted to std::string unless they are being operated on by a std::string operator (and even then, if I recall, they aren't so much promoted as the operator allows string/char* comparisons), so (std::string == char*) will perform the expected comparison operation. When we do std::string(char*), we call the std::string constructor, which returns a string (in this case, a temporary one) that is compared with your string literal.
Note that I am assuming incomming_data_buffer is of type char*, you are using it like it is, although I can't see the actual declaration.
I am trying to call on another program to perform a function (I have no idea what, only that it is not written in C++, but in shell) on a file within my C++ program. I do not know how to actually perform the function within my program. I do know that I write something like this
system(PROGRAM HERE);
The problem is that I do not know exactly how I am supposed to type the program out. I believe that if the function were to be called dostuff, I would type out
system("dostuff");
... I think. But what if there are arguments attached to that function that I would give as variables within my C++ program? That is what I would really need help with. In the terminal, I would type in "dostuff -1 arg". So in C++ would I type out
int arg = 5;
system("dostuff" arg);
You could format the string first. With <sstream> included:
int arg = 5;
std::stringstream ss;
ss << "dostuff " << arg;
system(ss.str().c_str());
Alternatively, you could use the concatenation feature of std::string. If you prefer the C-style formatters, you could use snprintf to similar effect.
Simple answer is
system("dostuff -1 5");
Essentially you need to construct the terminal argument and pass that to the system call.
Ex:
int arg = 5;
std::stringstream command;
command << "dostuff -1 " << arg;
system(command.str());
I would like to be able write code that looks like this:
int n;
std::string s = "some string";
SomeFunction("hello world" << n << " " << s << std::endl);
Where SomeFunction() is a method of some other class. The point is that I would like to be able to construct input for certain method using operator<<, just the way one'd do when writing to standard output in C++. How can I do that?
Thanks.
Your first parameter would have to be a home-made type that overloads operator<< and builds some kind of parameter list.
Your class would probably contain an ostream and would forward the operator<< to it.
If the function takes a string rather than your mysterious string-building object, you would then need to convert your object back to a string.
You could do it aleady with ostringstream like this:
int n;
std::string s;
std::ostringstream oss;
SomeFunction( ( oss << "hello world " << n << " " << s << '\n' ).str() );
Thanks, but this solution is way too obvious. I am looking for the code to remain the same as in the sample. – Alexander Sandler 54 secs ago
A surprising bias against obvious solutions?
Your syntax just cannot be achieved (in general[1]) without the macro that you describe in the first comment. Period.
[1] In specific cases you might be able to force the issue by overloading to ostream& operator<<(std::string, myspecifictype). In practice this will give you nothing but headaches because just about every use of the << operator will subsequently result in ambiguous overload resolutions