C++/European decimal-comma national setting
Expert: Ralph McArdell - 3/14/2008
QuestionHi ,
I've completed a program in MSVC++6 but have a problem in that it will only function in the American decimal-point setting and not the European decimal-comma setting. Both settings are important in the use of this program.
Though this is one of the first programs written in VC++, I am fairly competent in Visual Basic 6 in which I've written this program already. I've gone back over my old VB programs that were adapted to run with the decimal-comma setting and they run fine using the Swedish national setting setup from the control panel.
A good example of my problem is when constants are used in VB6, one of which is: dblcMeterConvert = 500000 / 25.4, dblcMeterConvert becomes 19685,039370079 but in VC++6, dblcMeterConvert = 19685.039370079 ignoring the European decimal-comma national setting and working only in decimal-point. I've checked help(MSDN) within MSVC++6, but found nothing. Do you know of any changes I should make within VC++6 to make it recognize and utilize the European decimal-comma national setting?
Thanks in advance for your help,
-Neil
AnswerI think what you are asking and what your example implies are somewhat different.
1/ What you example implies at least on first reading:
You example implies you have something like so:
double dblcMeterConvert(0.0);
dblcMeterConvert = 500000 / 25.4;
In this case the values used to calculate dblcMeterConvert are specified using C++ integer and floating point literal values and the latter always uses a US/UK style full stop (.) for the decimal point and not a (other) European style comma.
The value of dblcMeterConvert is stored in binary floating point format and so has no such formatting whatsoever.
2/ On the other hand if you wish to use such locale sensitive formatting for specific or system locale settings with C++ IOStreams to input and output data in locale specific formats then you have to imbue the stream object in question with the required locale.
The default locale, by the way, is the C locale which certainly has a US bias <g>; it has the name "C", and is also represented by the object returned by std::locale::classic(). The native system locale (presumably that set using system locale setting facilities) has an empty name (""). Specifically named locales have other names and are compiler (or rather C++ standard library) / system specific - for Microsoft systems use locale names such as "German_Germany.1252" and "Dutch_Netherlands.1252" or parts thereof such as "Dutch" or "French-Swiss".
Note that this information is mostly for ISO standard C++ in general. I have not had to make use of locales in MSVC++ 6.0 and no longer have that compiler to hand so cannot verify if these details apply to that specific compiler / library - however you should be able to find something (hopefully) in the MSDN library for the product in question. If not read the code - maybe debug and trace around the locale library code to see how it works. Also I took the above names from a book which explicitly mentions not only Microsoft systems but MSVC 6.0 (they actually printed MCV 6.0).
Therefore if you wish your application to pick up the current system locale settings you would create a locale object with an empty name and imbue your input and / or output streams with it thus:
#include <iostream>
#include <ios>
#include <locale>
int main()
{
double dblcMeterConvert(0.0);
dblcMeterConvert = 500000 / 25.4;
std::locale system_locale("");
std::cout.imbue(system_locale);
std::cout << "dblcMeterConvert = "
<< std::showpoint << dblcMeterConvert
<< std::endl;
return 0;
}
Or you can use a named locale, in which case replace:
std::locale system_locale("");
std::cout.imbue(system_locale);
With something like:
std::locale dutch_locale("Dutch");
std::cout.imbue(dutch_locale);
You can even use a temporary locale object:
std::cout.imbue( std::locale("Dutch") );
You can also set the locale globally:
std::locale::global( system_locale );
or:
std:: locale::global( std::locale("Dutch") );
However be wary of setting the global locale after objects have been created as they probably will not notice the change! Hence I would not expect std::cout to pick up the change of global locale before we use it in my example as it has most likely already been constructed and picked up its locale already.
Note that when I tested the example code using MSVC++ 8.0 (a.k.a. 2005) it seems that the default precision only allowed for one decimal place to be displayed, which was 0 and so was omitted by default, so I added a std::showpoint manipulator to force the display of the decimal point. There are other manipulators that are of interest here: std::noshowpoint clears the showpoint flag; std::fixed and std::scientific change the floating point display format to fixed point and scientific notation respectively and std::setprecision(n) changes the display precision to n significant digits (or n decimal places in the fractional part for scientific notation):
std::cout << std::scientific
<< std::setprecision(8)
<< fpValue
<< std::endl
;
Note that the IOStream library contains not only streams to read from and write to the console but also stream types to read and write to files and strings in memory - the latter may be of particular interest if you are formatting strings input from and displayed to a GUI.
I have only touched the very basics here. IOStreams and locales and the individual localisation facets that make up a locale are a large topic (which I found a bit scary until recently as I had never had time to read up on the details!). In addition to the C++ support there is also the legacy C locale support. And of course there is probably native operating system support - especially for non-UN*X like systems that use a C locale system such as - oh, yeah - Microsoft systems <g>.
I suggest you get yourself a good reference for the C++ standard library in general such as "The C++ Standard Library a Tutorial and Reference" by Nicolai M. Josuttis. For more detailed information specifically on IOStreams and locales there is "Standard C++ IOStreams and Locales" by Angelika Langer and Klaus Kreft.
Hope this at least gets you moving forward and provides references that you can expand on the brief information presented here.