0

I'm trying to fully understand how to use ostringstream to modernize some code that uses sprintf. The problem is in replacing test code that generates random or sequential data. Here's a simplified example:

char num[6], name[26];
sprintf(num, "%05d", i);
sprintf(name, "Customer # %d", i);

Leaving aside the minutia of length calculation, copying the result to the array and null-termination, the num conversion is straightforward:

ostringstream ostr;
ostr << setw(len) << setfill('0') << i;

For example, given i as 123, the result is "00123". However, for the name, which is actually a mixture of a char-string and an integer, I can't figure how to replicate what sprintf appears to do so easily. I tried variations of this:

ostr << setw(len) << left << "Customer # " << i << setfill(' ');

Given the same value for i, the result was always "Customer # 123", i.e., the integer always right justified, no matter what combination of left, right or internal, or the placement of the various parts. It seems the only solution (I haven't tried it yet), is to first concatenate the "Customer # " and the i onto a separate ostringstream and then insert that left justified to the ostr variable. Am I missing something? Is there some other way?


Correction: as discussed in the comments, in simplifying the example I overlooked a second sprintf that was actually responsible for right-padding the name. So a second output to the ostringsteam is also needed to accomplish that.

Joe Abbate
  • 1,692
  • 1
  • 13
  • 19
  • What is the purpose of `setw`? It does not correspond to anything in the corresponding `sprintf` call. – Sam Varshavchik Apr 15 '21 at 01:26
  • 3
    IO modifiers like `std::setw` only apply to call to `operator<<` that immediately follows them. – Brian61354270 Apr 15 '21 at 01:27
  • @Sam Varshavchik I'm afraid I simplified too much. The actual code does two sprintfs for the name, one as shown and a second to pad right with spaces, i.e., something like `sprintf(name + strlen(name), "%*.s", len - strlen(name), " ");` – Joe Abbate Apr 15 '21 at 01:37
  • `ostringstream` is not handy for complex formatting, give a try on the awesome `fmt` library – prehistoricpenguin Apr 15 '21 at 01:43
  • Based on Sam and Brian's comments above and my finding that a second sprintf is used, I guess the desired formatting could be achieved as follows: `ostr << left << "Customer # " << i; ostr << setw(len - ostr.str().size()) << setfill(' ') << " ";` – Joe Abbate Apr 15 '21 at 01:53
  • @JoeAbbate So the second one is `sprintf(name + strlen(name), "%*.s%s", len - strlen(name), " ", name);` so that name is right justified in a string of `len` length? If that's right we should edit the question. I think prehistoricpenguin is right - it's not easy - if you need two sprintf lines then you need two stringstreams. You should definitely look at the fmt library. – Jerry Jeremiah Apr 15 '21 at 03:26
  • `i.e., the integer always right justified, no matter what combination of left, right or internal` but it is always right justified in `sprintf(name, "Customer # %d", i);` I do not understand - why are you doing functionally different C++ code then C code? Why not `ostr << "Customer # " << i;`? `The actual code does two sprintfs for the name` Well, please do not post unrelated code then... Please include the expected output (ie. look after printing it out) for the input (ie. for `i=123`. – KamilCuk Apr 15 '21 at 10:12
  • @Jerry Jeremiah: Correction added. I've looked at {fmt} and it does look quite promising. – Joe Abbate Apr 15 '21 at 10:16
  • "How `ostringstream` does ...". It doesn't, really `ostringstream` is just an `ostream` which outputs to string, and the question would be the same for `std::cout`. – MSalters Apr 15 '21 at 10:17
  • Just in case you want to see what it looks like if you do use a temporary stringstream to build the string and then use a second one to justify it: https://onlinegdb.com/BJo6pmUUu – Jerry Jeremiah Apr 15 '21 at 21:19

0 Answers0