2

I have a Linux system that is set to some locale and its running a c++ application. I can do a std::setlocale(LC_NUMERIC, "en_US.UTF-8") from a c++ application or from OS itself (by changing at /etc/default/locale). I don't have access to main function, so i did std::setlocale(LC_NUMERIC, "en_US.UTF-8") in my function and it works fine.

However, i would like to do it an object level or at some global level (once) in my application. I looked quite a bit on internet but didn't find much help, so decided to ask. Here is my struct for GPS Position

So, basically

    //struct Position : std::numpunct<char> {
    struct Position {
    Position() { isValid = PR_FALSE; lat = 0; lng = 0; elevation = 0; };
    PRBool isValid;
    double lat;
    double lng;
    double elevation;
    //char do_decimal_point()   const { return '.'; }  // separate with slash
};

And then, in my function i do

mycheckposition(){

Position checkPosition;
Position mPosition;
// get some data in above.

double distance;
GetDistanceBetweenWGS84Coords(checkPosition, mPosition, distance);

}

My question is where should i do setlocale effectively and safely. My Position values gets comma instead of dot and then GetDistanceBetweenWGS84Coords fails. The LC_NUMERIC on my system represents comma for number with decimal. May be, if someone wants to see GetDistance function, here it is.

int GetDistanceBetweenWGS84Coords(const Position& from, const 
Position& to, double& distance)
{
const double EARTH_RADIUS_IN_METERS = 6372797.560856;
const double DEG_TO_RAD = 0.017453292519943295769236907684886;

double latitudeArc  = (from.lat - to.lat) * DEG_TO_RAD;
double longitudeArc = (from.lng - to.lng) * DEG_TO_RAD;
double latitudeH = sin(latitudeArc * 0.5);
latitudeH *= latitudeH;
double lontitudeH = sin(longitudeArc * 0.5);
lontitudeH *= lontitudeH;
double tmp = cos(from.lat*DEG_TO_RAD) * cos(to.lat*DEG_TO_RAD);

double arcInRadians = 2.0 * asin(sqrt(latitudeH + tmp*lontitudeH));
distance = EARTH_RADIUS_IN_METERS * arcInRadians;

return 0; //success
}

I did found something that solves my problem but haven't managed to get this working. Not sure if description in this link follows std lib.

ead
  • 32,758
  • 6
  • 90
  • 153
sb32134
  • 426
  • 8
  • 19
  • 1
    What's the problem? You're writing a plugin and it calls `setlocale` multiple times? Isn't there a setup hook that the application calls when loading the plugin? If not, just use a `bool` global to avoid calling it a second time. However, changing the application's locale might not be such good behavior for a plugin, so you might want to look into avoiding dependence on the locale, or using localized APIs such as `strtol_l`. – Potatoswatter Feb 03 '16 at 15:21
  • @Potatoswatter ```strtol_l ``` looks like something that could be useful. Is there any example somewhere i can look into? Or is it something as strtol. Also, there is a init function for my plugin but i did setlocale in there but it has no effect. For my case, setlocale only works if i do in as above or set LC_NUMERIC at OS. – sb32134 Feb 03 '16 at 15:29
  • 1
    I solved the problem with the following: ```std::istringstream istrLat(NS_ConvertUTF16toUTF8(value).get()); istrLat >> checkPosition.lat; ``` I got the hint from [here](http://stackoverflow.com/questions/1333451/locale-independent-atof). The important thing here is ```std::istringstream``` and as the link says correctly, the reasoning is "*The standard iostreams use the global locale by default (which in turn should be initialized to the classic (US) locale).*" – sb32134 Feb 04 '16 at 16:04

1 Answers1

2

I gave an answer for a similar problem some time ago and tried to clarify the problems with locale, so if you would like to know more: stod does not work correctly with boost::locale. In a nutshell:

  1. It is not a nice thing to call std::setlocale in your plug-in, because it is a global state for the whole application and you could mess up other parts of the application. At least you should reset the locale back as soon as you're done.

  2. If you use std::stream (stringstream, cin, cout), than the locale of the stream matches the value of the global C++ locale at the moment of the creation of the stream object. Normally it is the classical "C" locale. But there is no guaranty, because some part of the application could manipulate this, the same way as you did.

  3. you can make sure, that the std::stream has the desirable locale by invoking std::stream::imbue. This would only manipulate your stream and not the global state.

For example:

std::stringstream stream;
stream.imbue(std::locale::classic());//classical locale "C" with separator '.'
Community
  • 1
  • 1
ead
  • 32,758
  • 6
  • 90
  • 153
  • I tested your example, it works fine. basically its the same as the one in my link from comments above. But your point 3 is valid i.e. it makes sure with ```stream::imbue```. – sb32134 Feb 05 '16 at 11:34