Knihovna locale.h

K čemu je locale.h

Knihovna locale.h se stará o „národní prostředí“. V různých zemích se používají různé konvence pro různé věci. Tak napříkad někde se používá desetinná čárka, někde desetinná tečka. Někde se používá jako symbol měny $, někde se používá €, někde se zobrazuje datum ve formátu den/měsíc/rok, někde měsíc/rok/den (takže co znamená 07/01/14?) Locale obsahuje všechny možné informace pro všechny možné jazyky a země. Locale ovlivňuje i znakovou sadu.

Použití locale má své výhody i nevýhody. Výhoda je, že díky locale bude váš program mluvit domorodým jazykem uživatele. Nevýhoda je, že locale přinášejí i určitou nekompatibilitu. Představte si, že zapíšete do souboru čísla s desetinnou tečkou, ale s nastaveným locale jiné země se váš program bude snažit načíst data s desetinnou čárkou …

Locale ovlivňuje funkci některých knihovních funkcí jazyka C. Například printf() se na základě locale rozhodne, jestli vypsat desetinnou tečku nebo desetinnou čárku. Může ovlivňovat i nějaké nestandardní knihovní funkce, nebo vaše funkce, pokud si je tak naprogramujete.

Seznam locale

Locale je závislé na vašem operačním systému, resp. na tom, jaké locale (pro jaké země a jazyky) máte nainstalované. V linuxu si můžete vypsat nainstalované locale tímto příkazem:

$ locale -a
aa_DJ
aa_DJ.utf8
aa_ER
aa_ER@saaho
aa_ET
af_ZA
af_ZA.utf8
...
C
...
cs_CZ
cs_CZ.utf8
...
en_BE
en_BE@euro
en_BE.utf8
...
en_US
en_US.iso885915
en_US.utf8
...
POSIX
...
sk_SK
sk_SK.utf8
...

Výpis jsem zkrátil, protože by byl moc dlouhý. Vyspal jsem jen některé nejzajímavější locale. Je možné, že vás výpis bude mnohem kratší a budete mít naistalované třeba jenom locale pro cs_CZ.utf8, C a POSIX.

Bohužel, locale pro Windows nejsou stejné. A ještě víc bohužel, nenašel jsem nikde koretkní dokumentaci podporovaných locales ve Windows. Idkyž něco se vygooglit dá, např. Locale IDs, Input Locales, and Language Collections for Windows XP and Windows Server 2003, nebo Locale codes.

Podstatné na tom seznamu je, že např. locale pro ČR se jmenují Czech, pro SK Slovak, další jsou např. English_United_States nebo English_United_Kingdom. Tedy úplně jiné názvy než v Linuxu.

Jak už jsem psal, locale ovlivňuje i znakovou sadu, která je používána. Zatím jste se seznámili s ascii tabulkou, ale existují samozřejmě další, které obsahují znaky národních abeced (znaky s háčky a čárky, přehlasované a, u pro němčinu atd.).
V linuxu si můžete všimnout, že některé locale obsahují i název znakové sady. Např. cs_CZ.utf8 je locale pro českou republiku (cs) jazyk čeština (CZ) a znakovou sadu UTF8. Locale cs_CZ obsahuje znakovou sadu iso-8859-2. LOcale s touto znakovou sadou se využivalo v linuxu dříve, moderení systémy používají kódování UTF-8.

Locale ve Windows používají vlastní znakové sady, například Czech i Slovak použivají znakovou sadu windows-1250.

Proč existuje tolik znakových sad má své historické důvody. O znakových sadách ještě bude řeč, zatím je nemusíte nijak řešit.

Standardní locale

Existují 2 standardní locale dle ISO standardu jazyka C:

"C"
Toto je standardní locale jazyka C. S tímto locale bude váš program vždy číst i zapisovat čísla s desetinnou tečkou atp. Nemusíte se bát žádné nekompatibility. Toto locale je defaultní (je nastavené po spuštění programu)
""
Toto "locale" se používá pro nastavení locale dle operačního systému (tak, jak ho má nastavené uživatel).

Krom toho existuje ještě "POSIX", který je aktuálně pouze aliasem pro "C" a funguje jenom v systémech splňující standard POSIX, tedy ne ve Windows.

Kategorie locale

Locale ovlivňuje celou řadu vlastností. Tyto vlastnosti jsou rozděleny do několika kategorií. Každá z těchto kategorií může být v programu nastavena na jiné locale.

LC_COLLATE
Ovlivňuje pořadí při třídění znaků (funkce strcoll() a strxfrm()). Například čeština má "ch" mezi "h" a "i", jiné jazyky "ch" neznají.
LC_CTYPE
Ovlivňuje znakovou sadu. Například to, co je považováno za znak, za číslo, za bílý znak, za velké nebo malé písmeno atd.
LC_MONETARY
Ovlivňuje vše, co se týče peněz (např. znak pro měnu, jestli ze znak měny píše před číslo nebo za číslo atp.).
LC_NUMERIC
Ovlivňuje číselné hodnoty (které se netýkají peněz). Napříkald desetinná tečka vs desetinná čárka
LC_TIME
Ovlivňuje formátování data a času.
LC_MESSAGES
Ovlivňuje v jakém jazyce budou vypisovány standardní hlášky (např. chybové hlášky funkce perror())
LC_ALL
Nastaví/přepíše všechna locale najednou.
LANG
Jako LC_ALL, jenom nepřepíše již nastavené kategorie locale

Funkce setlocale()

Funkce setlocale() nastavuje locale (pokud nepředáte jako nové locale NULL) a vrací nastavené locale, nebo NULL (pokud se nastavit nedá).

char *setlocale(int category, const char *locale);

Funkce setlocale() nastavuje locale globálně, pro všechny spuštěné vlánka programu. To je trochu opruz. Pokud chcete změnit locale jen dočasně, musíte si poznamenat původní locale, nastavit nové a poté zase nastavit to původní. Navíc, protože se nastavuje pro všechna spuštěná vlákna, není možné, aby jedno vlákno pracovalo v jednom locale a druhé v jiném ve stejný okamžik. (O vláknech bude řeč v části věnované programování v Linuxu.)

Příklad:

/*------------------------------------------------*/
/* locale/locale1.c                               */

#include <stdio.h>
#include <errno.h>
#include <math.h>
#include <locale.h>

double logaritmus(double x)
{
    double y;
    y = log(x);

    switch (errno) {
    case 0:
        perror(NULL);
        printf("log(%f) = %f.\n", x, y);
        return y;
    default:
        perror("Hlaseni");
        return 0;
    }
}

void test_vystup() {
    printf("Cislo 10000/3 = %f\n", 10000.0/3);
    (void) logaritmus(-5);
    (void) logaritmus(0);
}

int main(void)
{
    printf("* Aktualne nastavene locale LC_ALL: %s\n", setlocale(LC_ALL, NULL));
    test_vystup();

    printf("* Locale LC_ALL nastaveno na: %s\n", setlocale(LC_ALL,""));
    test_vystup();

    printf("* Locale LC_NUMERIC nastaveno na %s\n", setlocale(LC_NUMERIC,"C"));
    test_vystup();

    return 0;
}

/*------------------------------------------------*/

Program využívá knihovnu math.h a proto musí být v Linuxu přeložen s volbou -lm:
gcc -o locale1 locale1.c -lm -Wall

* Aktualne nastavene locale LC_ALL: C
Cislo 10000/3 = 3333.333333
Hlaseni: Numerical argument out of domain
Hlaseni: Numerical result out of range
* Locale LC_ALL nastaveno na: cs_CZ.UTF-8
Cislo 10000/3 = 3333,333333     // Desetinná čárka
Hlaseni: Číselný rozsah mimo definiční obor funkce
Hlaseni: Číselný výsledek mimo rozsah
* Locale LC_NUMERIC nastaveno na C
Cislo 1/3 = 0.333333    // Desetinná tečka
Hlaseni: Číselný rozsah mimo definiční obor funkce
Hlaseni: Číselný výsledek mimo rozsah

Za domácí úkol si vyzkoušejte, jak locale ovlivní výstup funkce strftime().

Funkce localeconv()

Funkce localeconv() vrací několik informací o nastaveném locale. Moc zajímavých informací to není, ale aspoň něco. Nic lepšího bohužel locale.h nenabízí.

struct  lconv *localeconv (void);

Návratovou hodnotou je odkaz na strukturu struct lconv, která obsahuje minimálně tyto položky:

char    *currency_symbol
char    *decimal_point
char     frac_digits
char    *grouping
char    *int_curr_symbol
char     int_frac_digits
char     int_n_cs_precedes
char     int_n_sep_by_space
char     int_n_sign_posn
char     int_p_cs_precedes
char     int_p_sep_by_space
char     int_p_sign_posn
char    *mon_decimal_point
char    *mon_grouping
char    *mon_thousands_sep
char    *negative_sign
char     n_cs_precedes
char     n_sep_by_space
char     n_sign_posn
char    *positive_sign
char     p_cs_precedes
char     p_sep_by_space
char     p_sign_posn
char    *thousands_sep

Příklad:

/*------------------------------------------------*/
/* locale/locale2.c                               */

#include <stdio.h>
#include <locale.h>

void test_vystup(void) {
        struct lconv *lconv;
        lconv = localeconv();
        printf("Locale: %s\n",setlocale(LC_ALL, NULL));
        printf("Penezni symbol:   %s\n", lconv->currency_symbol);
        printf("Desetinny symbol: %s\n", lconv->decimal_point);
        printf("Oddelovac tisicu: '%s'\n", lconv->thousands_sep);
        printf("\n");
}

int main(void)
{
        test_vystup();
        setlocale(LC_ALL, "");
        test_vystup();
        setlocale(LC_NUMERIC, "C");
        test_vystup();

        return 0;
}

/*------------------------------------------------*/

Výstup z programu:

Locale: C
Penezni symbol:   
Desetinny symbol: .
Oddelovac tisicu: ''

Locale: cs_CZ.UTF-8
Penezni symbol:   Kč
Desetinny symbol: ,
Oddelovac tisicu: ' '

Locale: LC_CTYPE=cs_CZ.UTF-8;LC_NUMERIC=C;LC_TIME=cs_CZ.UTF-8;LC_COLLATE=cs_CZ.UTF-8;LC_MONETARY=cs_CZ.UTF-8;LC_MESSAGES=cs_CZ.UTF-8;LC_PAPER=cs_CZ.UTF-8;LC_NAME=cs_CZ.UTF-8;LC_ADDRESS=cs_CZ.UTF-8;LC_TELEPHONE=cs_CZ.UTF-8;LC_MEASUREMENT=cs_CZ.UTF-8;LC_IDENTIFICATION=cs_CZ.UTF-8
Penezni symbol:   Kč
Desetinny symbol: .
Oddelovac tisicu: ''

Výstup z programu přeloženém Visual Studiem (tedy ve Windows):

Locale: C
Penezni symbol:
Desetinny symbol: .
Oddelovac tisicu: ''

Locale: Czech_Czech Republic.1250
Penezni symbol:   Kč
Desetinny symbol: ,
Oddelovac tisicu: ' '

Locale: LC_COLLATE=Czech_Czech Republic.1250;LC_CTYPE=Czech_Czech Republic.1250;
LC_MONETARY=Czech_Czech Republic.1250;LC_NUMERIC=C;LC_TIME=Czech_Czech Republic.
1250
Penezni symbol:   Kč
Desetinny symbol: .
Oddelovac tisicu: ''
Komentář Hlášení chyby
Created: 1.7.2014
Last updated: 1.7.2014
Tato stánka používá ke svému běhu cookies, díky kterým je možné monitorovat, co tu provádíte (ne že bych to bez cookies nezvládl). Také vás tu bude špehovat google analytics. Jestli si myslíte, že je to problém, vypněte si cookies ve vašem prohlížeči, nebo odejděte a už se nevracejte :-). Prohlížením tohoto webu souhlasíte s používáním cookies. Dozvědět se více..