Заставьте gzprintf игнорировать локаль LC_NUMERIC - PullRequest
0 голосов
/ 08 ноября 2018

Как я могу заставить gzprintf (или printf в целом) использовать "." в качестве десятичного разделителя, эффективно игнорируя LC_NUMERIC или используя "LC_NUMERIC = C".

Справочная информация: Моя программа, которая использует gettext, делает setlocale (LC_ALL, ....), чтобы изменить ее локаль. Но в какой-то момент мне нужно записать в файл измерений, который должен иметь фиксированное "." в качестве десятичного разделителя. Конечно, я могу сделать что-то вроде

const char *old = setlocale (LC_NUMERIC, NULL);
... make copy
setlocale (LC_NUMERIC, "C");
... use gzprintf
setlocale (LC_NUMERIC, old_copy);

но я боюсь проблем во время выполнения, потому что мне нужно записать в файл сэмплы с частотой 2 кГц, но я еще не тестировал их.

1 Ответ

0 голосов
/ 08 ноября 2018

Мало того, что завершение каждого вызова setlocale, возможно, слишком медленно. Это совершенно поточно-небезопасно и, следовательно, небезопасно для использования в общем / библиотечном коде.

Если вы работаете в POSIX или POSIX-подобной системе, вам нужно newlocale / uselocale. Выполните следующее (что может быть медленным) один раз и сохраните результат:

locale_t safe_locale = newlocale(LC_NUMERIC_MASK, "C", duplocale(LC_GLOBAL_LOCALE));

Тогда, когда вы захотите использовать:

locale_t old = uselocale(safe_locale);
/* Do stuff with it. */
uselocale(old);

Вам не нужно переключаться вперед и назад вокруг каждой операции, только перед тем, как вернуться к вызывающему абоненту, который может ожидать, что его языковой стандарт не будет нарушен, но в любом случае он не должен медленно переключаться назад и вперед, как это.

В качестве альтернативы, просто не учитывайте LC_NUMERIC в вашем приложении. После вызова setlocale(LC_ALL, ""), чтобы установить языковой стандарт в соответствии с настройками пользователя, позвоните setlocale(LC_NUMERIC, "C") и оставьте все как есть. Это недопустимо / неприемлемо в библиотечном коде, но если вы пишете библиотечный код, вы можете решить и позволить вызывающей стороне взять на себя ответственность за любой подход, который он сочтет подходящим (никогда не соблюдая LC_NUMERIC вообще, или используя newlocale / uselocale для переключения). Вы можете либо просто записать это требование в документацию к его контракту, и трактовать несоблюдение контракта как неопределенное, либо вы можете активно проверять точку, отличную от '.', утверждая, что localeconv()->decimal_point указывает на строку "." (и возвращает ошибку или прерывает работу, если она не удерживается).

...