C++: How to Get Fprintf Results as a Std::String W/O Sprintf

C++: how to get fprintf results as a std::string w/o sprintf

I am using #3: the boost string format library - but I have to admit that I've never had any problem with the differences in format specifications.

Works like a charm for me - and the external dependencies could be worse (a very stable library)

Edited: adding an example how to use boost::format instead of printf:

sprintf(buffer, "This is a string with some %s and %d numbers", "strings", 42);

would be something like this with the boost::format library:

string = boost::str(boost::format("This is a string with some %s and %d numbers") %"strings" %42);

Hope this helps clarify the usage of boost::format

I've used boost::format as a sprintf / printf replacement in 4 or 5 applications (writing formatted strings to files, or custom output to logfiles) and never had problems with format differences. There may be some (more or less obscure) format specifiers which are differently - but I never had a problem.

In contrast I had some format specifications I couldn't really do with streams (as much as I remember)

std::string formatting like sprintf

You can't do it directly, because you don't have write access to the underlying buffer (until C++11; see Dietrich Epp's comment). You'll have to do it first in a c-string, then copy it into a std::string:

  char buff[100];
snprintf(buff, sizeof(buff), "%s", "Hello");
std::string buffAsStdStr = buff;

But I'm not sure why you wouldn't just use a string stream? I'm assuming you have specific reasons to not just do this:

  std::ostringstream stringStream;
stringStream << "Hello";
std::string copyOfStr = stringStream.str();

Best way to safely printf to a string?

This StackOverflow question has a similar discussion. Also in that question I present my favorite solution, a "format" function that takes identical arguments to printf and returns a std::string.

Proper use of fprintf

It is acceptable if you "know" the string variable to be "clean", if you don't care about the warning most modern compilers generate for that construct. Because:

  1. If your string contains conversion specifiers "by accident", you are invoking undefined behaviour.

  2. If you read that string from somewhere, a malicious attacker could exploit point 1. above to his ends.

It's generally better to use puts() or fputs() as they avoid this problem, and consequently don't generate a warning. (puts() also tosses in an automatic '\n'.)

The *puts() functions also have (marginally) better performance. *printf(), even on nothing more than "%s" as format string, still has to parse that conversion specifier, and count the number of characters printed for its return value.

Thanks to users 'rici' and 'Grady Player' for pointing out the character counting and compiler warning. My C got a bit rusty it seems. ;-)

printf with std::string?

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.

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:

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:

#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.


[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.

fprintf() / std::cout doesn't print part of the string to stdout/stderr

I use boost::asio, I have a callback to read from stdin. this read is nonblocking - happens with async_read_some().

The problem was stdin was turned to be nonblocking, and it also caused stdout to be nonblocking as well because they point to the same file description (explanation).

It caused the fprintf() calls to fail (returned -1 with errno 11) and not all of the output got printed out on the screen.

It has no relation to boost.

I succeeded isolating the problem, the following code creates this problem:

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>

using namespace std;

int main(int argc, char *argv[]) {

const int problem = 8000;
const int myBuffSize = 32000;
char *myBuff = new char[myBuffSize];
int myoffset = 0;
memset(myBuff, '-', myBuffSize);
int flags;

bool toogle = true;
bool running = true;

// Comment from here
if ((flags = fcntl(STDIN_FILENO, F_GETFL, 0)) < 0) {

printf("error fcntl()\n");
return 0;
}
if (fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK) < 0) {
printf("error fcntl()\n");
return 0;
}
// Comment until here

while(running) {

toogle = toogle ? false : true;
if (toogle) {

snprintf(myBuff + problem, myBuffSize - problem, "fin\n\n");
} else {
snprintf(myBuff + problem, myBuffSize - problem, "end\n\n");
}
fprintf(stdout, "%s", myBuff);
sleep(1);
}

delete[] myBuff;
return 0;
}

If you'll comment the // Comment from here to // Comment untill here, it will print all of the output (fin and end will be printed).

One solution to this problem is to open another fd to the current tty using fopen(ttyname(STDOUT_FILENO), "w") and to print into it.

I believe another solution is to async_write() into screen.

Use sprintf with fixed width, left-justified field and concatenation

You could split your sprintf's (and, in the meantime, use snprintf instead, for safety), and use the return value of the previous one to know exactly how much characters have been printed.

Something like that :

// Will split in columns = 10, 50, 60
void formatMyString(int num, char *name, int counter, float setval, float mes)
{
char buf[256] = {0};
int cnt = 0;
cnt = snprintf(buf, 256-cnt, "%i ", num);
if (cnt < 10) {
memset(&buf[cnt], ' ', 10-cnt);
cnt = 10;
}
cnt += snprintf(&buf[cnt], 256-cnt, "%s_setup%i ", name, counter);
if (cnt < 50) {
memset(&buf[cnt], ' ', 50-cnt);
cnt = 50;
}
cnt += snprintf(&buf[cnt], 256-cnt, "%2.2f ", setval);
if (cnt < 60) {
memset(&buf[cnt], ' ', 60-cnt);
cnt = 60;
}
snprintf(&buf[cnt], 256-cnt, "%2.2f", mes);
printf("%s\n", buf);
}

This should work. You can change the split columns by changing the constants, and adjust for thour format.
If the inputs are longer than the expected size, then no padding is done.

String format works in fprintf but doesn't work in sprintf, gives segmentation fault

You are not allocating memory for stat. Try

char *stat = malloc(MAXLEN);
snprintf(stat, MAXLEN, ...);
^ ^

how to specify multiple format string in fprintf function?

Use a for loop. That will be able to print 100 floating point numbers

fprintf: print literal hex string

You'll have to convert the std::string to a null-terminated const char* using its c_str() member function:

fprintf(stdout,"foo=%s",s.c_str());

Note that this is still C++, even if you use fprintf(). C does not contain a data type std::string.



Related Topics



Leave a reply



Submit