2016-02-03 6 views
2

У меня есть система Linux, которая настроена на некоторую локаль и запускает приложение C++. Я могу сделать std::setlocale(LC_NUMERIC, "en_US.UTF-8") из приложения C++ или из самой ОС (путем изменения на /etc/default/locale). У меня нет доступа к основной функции, поэтому я сделал std::setlocale(LC_NUMERIC, "en_US.UTF-8") в моей функции, и он отлично работает.Использование setlocale на уровне объекта или на уровне приложения

Однако, я хотел бы сделать это на уровне объекта или на каком-то глобальном уровне (один раз) в моем приложении. Я немного поглядел в интернете, но не нашел большой помощи, поэтому решил спросить. Вот моя структура для GPS позиции

Таким образом, в основном

//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 
}; 

И тогда, в моей функции я сделать

mycheckposition(){ 

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

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

} 

Мой вопрос, где я должен делать Setlocale эффективно и безопасно. Значения «Моя позиция» получают запятую вместо точки, а затем GetDistanceBetweenWGS84Coords терпит неудачу. LC_NUMERIC в моей системе представляет запятую для числа с десятичной запятой. Может быть, если кто-то хочет увидеть функцию GetDistance, вот она.

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 
} 

Я нашел что-то, что решает мою проблему, но не удалось получить эту работу. Не уверен, что описание в this ссылается на std lib.

+1

В чем проблема? Вы пишете плагин и многократно называет 'setlocale'? Разве нет привязки настройки, которую приложение вызывает при загрузке плагина? Если нет, просто используйте глобальный 'bool', чтобы избежать вызова его во второй раз. Однако изменение локали приложения может быть не таким хорошим поведением для плагина, поэтому вам может понадобиться избегать зависимости от локали или использовать локализованные API, такие как 'strtol_l'. – Potatoswatter

+0

@Potatoswatter '' 'strtol_l' '' выглядит как-то, что может быть полезно. Есть ли какой-нибудь пример, где я могу заглянуть? Или это что-то вроде strtol. Кроме того, есть функция init для моего плагина, но я сделал setlocale там, но он не имеет никакого эффекта. Для моего случая, setlocale работает только в том случае, если я делаю это выше или устанавливаю LC_NUMERIC в ОС. – sb32134

+1

Я решил проблему со следующим: '' 'std :: istringstream istrLat (NS_ConvertUTF16toUTF8 (значение) .get()); istrLat >> checkPosition.lat; '' 'Я получил подсказку [здесь] (http://stackoverflow.com/questions/1333451/locale-independent-atof). Здесь важна '' 'std :: istringstream''', и, поскольку ссылка говорит правильно, аргументация« * Стандартные iostreams используют глобальный язык по умолчанию (который, в свою очередь, должен быть инициализирован в классическом (US) локали). * « – sb32134

ответ

1

Я дал ответ на аналогичную проблему некоторое время назад и попытался прояснить проблемы с локалью, поэтому, если вы хотите узнать больше: stod does not work correctly with boost::locale. В двух словах:

  1. Это не хорошая вещь, чтобы позвонить std::setlocale в вашем плагине, потому что это глобальное состояние для всего приложения, и вы могли бы испортить другие части приложения. По крайней мере, вы должны сбросить языковой стандарт, как только вы закончите.

  2. Если вы используете std::stream (stringstream, cin, cout), чем локали потока соответствует значению глобальной локализации C++ в момент создания объекта потока. Обычно это классический «C» язык. Но нет никакой гарантии, потому что какая-то часть приложения могла бы манипулировать этим, так же, как и вы.

  3. вы можете быть уверены, что std::stream имеет желательный язык, вызывая std::stream::imbue. Это будет управлять вашим потоком, а не глобальным состоянием.

Например:

std::stringstream stream; 
stream.imbue(std::locale::classic());//classical locale "C" with separator '.' 
+0

Я проверил ваш пример, он отлично работает. в основном это то же самое, что и в моей ссылке из комментариев выше. Но ваш пункт 3 действителен, т. Е. Он уверен в '' 'stream :: imbue'''. – sb32134

Смежные вопросы