ATTENTION: You are viewing a page formatted for mobile devices; to view the full web page, click HERE.

Main Area and Open Discussion > Living Room

Numeric Format Strings in C++

(1/2) > >>

Stoic Joker:
Greetings
   I have spent the last several months working on a network scanner that will (quickly) search a network for any & all Print devices and then collect information from/about them (It'll do about 20 IP Addresses per second).

   As usual I am working in Pure Win32 API C++ e.g. No cs, No .NET, No MFC. ...and... I've completely hit the wall on one seemingly simple (but key) point.  I can not get the numeric string formatting to output a string like: 1,254.00

I'm passing a dollar amount stored in a double into StringCbPrintf(...) using %0.2f in the format string which gives me 1254.00 ...But I've gota have the blasted coma's in there or the Corporate Board Room types will whine and gnash their teeth.

Anyone have a clue what I'm missing?

Thank you,
Stoic Joker

mwb1100:
If you're using streams (cout, stringstream, etc.) to perform the I/O or formatting, what you want to do is call the stream's imbue() method with the proper locale.

As an aside - you should never use floats or doubles to deal with monetary amounts, of course...

Something like:


--- Code: C++ ---#include <locale>#include <iostream> using namespace std; int main(){    locale loc( ""); // user's locale    locale prev_loc( cout.imbue( loc)); // set stream's new locale and remember the origial ("global") locale        int dollars = 4561254;    int cents = 75;        cout << dollars << "." << cents << endl;        cout.imbue( prev_loc);         return 0;}
If you're not using streams (maybe you're a fan of printf-like formatting) then you might try adding the ' (single quote) character to the flags in the format specifier.  Some implementations take that to mean that the output should use thousands separators (Microsoft's compiler does not support this).

If the compiler you're using does not support that extension, the open source Trio library might be an option for you if you want to go this route, since it does support it:

http://daniel.haxx.se/projects/trio/

Stoic Joker:
Greetings
   And thanks for the input ... But I'm a bit confused on one point (not to side track myself...). Why not use doubles for dealing with money? The app I working on is the 2nd half of the total project that generates billing reports for 1,000 line items that are all being billed at $00.01 per x. If I used int I'd end up pointer casting everything multiple times and still probably not get the right answer.

   I guess I should also mention that this is a GUI application, so unless I'm badly miss-informed (which has happened...) all the cout stuff is strictly for CLI apps ... Correct?

GetDlgItemInt(...) automatically rounds off the "int" to the nearest whole number so 0.010 becomes 0
GetDlgItemText(...) dumped into atof() (which requires float or double) will actually give me 0.010 as a numeric value that I can then use.

The answer I ended up finding (at 1:30am) was to just run the string through
GetCurrencyFormat(LOCALE_USER_DEFAULT, 0, szNowFormatted, NULL, szString, ARRAYSIZE(szString));
Which is giving me the 1,234.01 format I was after.

Note: I'm using MSVC from MSVS and all the documentation on the MSDN seems to be split between two warring factions:

1. Says to use %n to get the thousands separators.

2. says never use %n because it's "unsafe" and has been depreciated. ...hence my quandary. ...Because none of the aforementioned documentation even hinted at the alternative, which was the API I (am using) mentioned above.

I'm not married to it ... so if there is a better way let me know.

Thank you,
Stoic Joker

mouser:
I had a hard time finding a good essay saying why not to use floats for money, but it's great that mwb raised this issue with you.  It's not an obvious thing, but it is quite important that you avoid using floating point for money if at all possible.

Here's one short piece on why: http://everything2.com/index.pl?node_id=803770

Basically the problem is that floating point variables were not designed to store exact values at arbitrary precision, and you can get some very unintuitive and weird rounding errors.  In the case of money, you almost always want to deal with an atomic value of 1 cent, and you dont care about fractions of cents, but you DO care about losing a penny here or there.  In such cases you should use an integer variable that holds the number of cents in the amount. (1 dollar stores as 100).  That lets you work with exact integer arithmetic.

mwb1100:
What Mouser said about using float/doubles for currency.

As far as some of the other things you brought up:


* I'm not sure exactly how %n is used to perform thousands grouping, but the reason it's deprecated (generally shouldn't be used) is that it's easy to introduce bugs that trash the stack which can lead to security errors.
* As far as using streams in GUI applications, you are right that "cout" is something that is pretty much not usable, but you can use stringstreams where the formatted output gets put into a string variable instead of getting sent to stdout (sort of like the difference between printf() and sprintf()).  See the end of this post for my sample modified to use stringstreams.
* I wasn't aware of GetCurrencyFormat() - that looks to be a pretty good solution. I think I would probably write a wrapper for it that took an int value in cents (or whatever lowest denominator currency you're using) so floats could be avoided, formatted a string with the decimal point in the right place then sent that string off to GetCurrencyFormat() to do the rest of the work.
Just for reference, here's the sample using stringstreams (though I think a GetCurrencyFormat() wrapper is the way I'd go):


--- Code: C++ ---#include <locale>#include <sstream>#include <string>#include <stdio.h> using namespace std; int main(){    stringstream formatted_string;     locale loc( ""); // user's locale    locale prev_loc( formatted_string.imbue( loc)); // set stream's new locale and remember the origial ("global") locale        int dollars = 4561254;    int cents = 75;            formatted_string << dollars << "." << cents << endl;        printf( "%s\n", formatted_string.str().c_str());        formatted_string.imbue( prev_loc);     return 0;}

Navigation

[0] Message Index

[#] Next page

Go to full version