グローバル C++ ロケールを設定すると、C ロケールも変更されます。C ロケールを変更しても、グローバル C++ ロケールは変更されません。
以下は、C++ グローバル ロケールの設定を示しています。
#include <cstdio>
#include <clocale>
#include <fstream>
int main() {
const char * locale_name = "French_France.1252"; // or "fr_Fr.UTF-8" on Unix
double value = 1.2;
std::locale::global(std::locale(locale_name));
std::ofstream("out.txt") << "C++ " << value << '\n';
if (FILE *f = std::fopen("out.txt", "a")) {
std::fprintf(f, "C %1.1e\n", value);
std::fclose(f);
}
}
C と C++ の両方の出力で、コンマ小数点を使用する必要があります。
C++ 1,2
C 1,2e+000
C++ ロケールの設定を C ロケールの設定に置き換えるとstd::setlocale(LC_ALL, locale_name);
、出力が変更され、C 出力のみがコンマ 10 進数を使用し、C++ 出力では引き続きデフォルトのピリオド小数点記号が使用されるようになります。
C++ 1.2
C 1,2e+000
ただし、C++ ロケールの設定が C ロケールに影響するという事実は、C ロケールが C++ ロケールのように拡張可能になるわけではありません。カスタム C++ ファセットは、C ロケール ベースの関数では使用されません。代わりに、必要な機能を持つ名前付きロケールをサポートするシステムに依存する必要があります。
具体的にstd::locale::global()
は、名前がある場合、選択した C++ ロケールの名前を使用して C ロケールを設定するように定義されています。C++ ロケールに名前がない場合、動作は実装定義です。また、C++ は、2 つの名前付きロケールを結合すると名前付きロケールが生成されることを指定します。一部の実装では、C++ ロケールを設定するだけで C ロケール カテゴリを混在させることができる便利な結合名が生成されます。
std::locale::global(std::locale(std::locale("ru_RU"), "C", std::locale::numeric));
libstdc++ を使用すると、次の名前のロケールが生成されます。
LC_CTYPE=ru_RU;LC_NUMERIC=C;LC_TIME=ru_RU;LC_COLLATE=ru_RU;LC_MONETARY=ru_RU;LC_MESSAGES=ru_RU;LC_PAPER=ru_RU;LC_NAME=ru_RU;LC_ADDRESS=ru_RU;LC_TELEPHONE=ru_RU;LC_MEASUREMENT=ru_RU;LC_IDENTIFICATION=ru_RU LC_CTYPE=ru_RU ;LC_NUMERIC=C;LC_TIME=ru_RU;LC_COLLATE=ru_RU;LC_MONETARY=ru_RU;LC_MESSAGES=ru_RU;LC_PAPER=ru_RU;LC_NAME=ru_RU;LC_ADDRESS=ru_RU;LC_TELEPHONE=ru_RU;LC_MEASUREMENT=ru_RU;LC_IDENTIFICATION=ru_RU
そのため、C ロケールは、C++ ロケールと同じ「ru_RU」ロケールと「C」ロケールの混合に設定されます。
残念ながら、他の実装では、技術的には準拠しているものの、あまり有用でない動作が選択されます。Visual Studio で
std::locale::global(std::locale(std::locale("Russian_Russia.1251"), "C", std::locale::numeric));
「C」という名前のロケールを生成します。そのため、C++ ロケールはロシア語と C ロケール カテゴリの適切な混合ですが、C ロケールは単純に「C」に設定されています。したがって、これらのプラットフォームで C ロケール カテゴリを混在させるには、C ロケールを直接設定する必要があります。
// set the C++ locale first
std::locale::global(std::locale(std::locale("Russian_Russia.1251"), "C", std::locale::numeric));
// set the C locale second, because it will not overwrite the changes you made to the C++ locale
std::setlocale(LC_ALL, "Russian_Russia.1251");
std::setlocale(LC_NUMERIC, "C");