【问题标题】:Using setlocale at object level or at application level在对象级别或应用程序级别使用 setlocale
【发布时间】:2016-02-03 15:15:58
【问题描述】:

我有一个设置为某些语言环境的 Linux 系统,它正在运行一个 c++ 应用程序。我可以从 c++ 应用程序或操作系统本身(通过更改 /etc/default/locale)执行 std::setlocale(LC_NUMERIC, "en_US.UTF-8")。我无法访问主要功能,所以我在我的功能中做了std::setlocale(LC_NUMERIC, "en_US.UTF-8"),它工作正常。

但是,我想在我的应用程序中以对象级别或某个全局级别(一次)执行此操作。我在网上看了很多,但没有找到太多帮助,所以决定问问。这是我的 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 链接中的描述是否遵循标准库。

【问题讨论】:

  • 有什么问题?您正在编写一个插件并且它多次调用setlocale?加载插件时没有应用程序调用的设置挂钩吗?如果没有,只需使用 bool 全局以避免第二次调用它。但是,更改应用程序的语言环境对于插件来说可能不是很好的行为,因此您可能需要考虑避免对语言环境的依赖,或者使用本地化 API,例如 strtol_l
  • @Potatoswatter strtol_l 看起来很有用。有什么我可以研究的例子吗?或者它是strtol。此外,我的插件有一个 init 函数,但我在那里做了 setlocale 但它没有效果。就我而言,setlocale 仅在我按上述方式执行或在操作系统中设置 LC_NUMERIC 时才有效。
  • 我用以下方法解决了这个问题:std::istringstream istrLat(NS_ConvertUTF16toUTF8(value).get()); istrLat &gt;&gt; checkPosition.lat; 我从here 得到了提示。这里重要的是std::istringstream,正如链接正确显示的那样,原因是“标准 iostreams 默认使用全局语言环境(反过来应该初始化为经典(美国)语言环境)。"

标签: c++ locale


【解决方案1】:

前段时间我给出了一个类似问题的答案,并试图澄清语言环境的问题,所以如果你想了解更多:stod does not work correctly with boost::locale。简而言之:

  1. 在您的插件中调用std::setlocale 不是一件好事,因为它是整个应用程序的全局状态,您可能会弄乱应用程序的其他部分。至少您应该在完成后立即重置语言环境。

  2. 如果使用std::streamstringstreamcincout),则流的语言环境与创建流对象时的全局 C++ 语言环境的值相匹配.通常它是经典的“C”语言环境。但是没有保证,因为应用程序的某些部分可以操纵它,就像你做的那样。

  3. 您可以通过调用std::stream::imbue 来确保std::stream 具有所需的语言环境。这只会操纵您的流而不是全局状态。

例如:

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

【讨论】:

  • 我测试了你的例子,效果很好。基本上它与我上面 cmets 的链接中的相同。但是您的第 3 点是有效的,即它确保使用 stream::imbue
猜你喜欢
  • 2011-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多