Prev | Contents | Next

12 <locale.h> locale handling

Function Description
setlocale() Set the locale
localeconv() Get information about the current locale

The “locale” is the details of how the program should run given its physical location on the planet.

For example, in one locale, a unit of money might be printed as $123, and in another €123.

Or one locale might use ASCII encoding and another UTF-8 encoding.

By default, the program runs in the “C” locale. It has a basic set of characters with a single-byte encoding. If you try to print UTF-8 characters in the C locale, nothing will print. You have to switch to a proper locale.

12.1 setlocale()

Set the locale


#include <locale.h>

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


Sets the locale for the given category.

Category is one of the following:

Category Description
LC_ALL All of the following categories
LC_COLLATE Affects the strcoll() and strxfrm() functions
LC_CTYPE Affects the functions in <ctype.h>
LC_MONETARY Affects the monetary information returned from localeconv()
LC_NUMERIC Affects the decimal point for formatted I/O and formatted string functions, and the monetary information returned from localeconv()
LC_TIME Affects the strftime() and wcsftime() functions

And there are three portable things you can pass in for locale; any other string passed in is implementation-defined and non-portable.

Locale Description
"C" Set the program to the C locale
"" (Empty string) Set the program to the native locale of this system
NULL Change nothing; just return the current locale
Other Set the program to an implementation-defined locale

The most common call, I’d wager, is this:

// Set all locale settings to the local, native locale

setlocale(LC_ALL, "");

Handily, setlocale() returns the locale that was just set, so you could see what the actual locale is on your system.

Return Value

On success, returns a pointer to the string representing the current locale. You may not modify this string, and it might be changed by subsequent calls to setlocale().

On failure, returns NULL.


Here we get the current locale. Then we set it to the native locale, and print out what that is.

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

int main(void)
    char *loc;

    // Get the current locale
    loc = setlocale(LC_ALL, NULL);

    printf("Starting locale: %s\n", loc);

    // Set (and get) the locale to native locale
    loc = setlocale(LC_ALL, "");
    printf("Native locale: %s\n", loc);

Output on my system:

Starting locale: C
Native locale: en_US.UTF-8

Note that my native locale (on a Linux box) might be different from what you see.

Nevertheless, I can explicitly set it on my system without a problem, or to any other locale I have installed:

    loc = setlocale(LC_ALL, "en_US.UTF-8");   // Non-portable

But again, your system might have different locales defined.

See Also

localeconv(), strcoll(), strxfrm(), strftime(), wcsftime(), printf(), scanf(), <ctype.h>

12.2 localeconv()

Get information about the current locale


#include <locale.h>

struct lconv *localeconv(void);


This function just returns a pointer to a struct lconv, but is still a bit of a powerhouse.

The returned structure contains tons of information about the locale. Here are the fields of struct lconv and their meanings.

First, some conventions. In the field names, below, a _p_ means “positive”, and _n_ means “negative”, and int_ means “international”. Though a lot of these are type char or char*, most (or the strings they point to) are actually treated as integers21.

Before we go further, know that CHAR_MAX (from <limits.h>) is the maximum value that can be held in a char. And that many of the following char values use that to indicate the value isn’t available in the given locale.

Field Description
char *mon_decimal_point Decimal pointer character for money, e.g. ".".
char *mon_thousands_sep Thousands separator character for money, e.g. ",".
char *mon_grouping Grouping description for money (see below).
char *positive_sign Positive sign for money, e.g. "+" or "".
char *negative_sign Negative sign for money, e.g. "-".
char *currency_symbol Currency symbol, e.g. "$".
char frac_digits When printing monetary amounts, how many digits to print past the decimal point, e.g. 2.
char p_cs_precedes 1 if the currency_symbol comes before the value for a non-negative monetary amount, 0 if after.
char n_cs_precedes 1 if the currency_symbol comes before the value for a negative monetary amount, 0 if after.
char p_sep_by_space Determines the separation of the currency symbol from the value for non-negative amounts (see below).
char n_sep_by_space Determines the separation of the currency symbol from the value for negative amounts (see below).
char p_sign_posn Determines the positive_sign position for non-negative values.
char p_sign_posn Determines the positive_sign position for negative values.
char *int_curr_symbol International currency symbol, e.g. "USD ".
char int_frac_digits International value for frac_digits.
char int_p_cs_precedes International value for p_cs_precedes.
char int_n_cs_precedes International value for n_cs_precedes.
char int_p_sep_by_space International value for p_sep_by_space.
char int_n_sep_by_space International value for n_sep_by_space.
char int_p_sign_posn International value for p_sign_posn.
char int_n_sign_posn International value for n_sign_posn.

Even though many of these have char type, the value stored within is meant to be accessed as an integer.

All the sep_by_space variants deal with spacing around the currency sign. Valid values are:

Value Description
0 No space between currency symbol and value.
1 Separate the currency symbol (and sign, if any) from the value with a space.
2 Separate the sign symbol from the currency symbol (if adjacent) with a space, otherwise separate the sign symbol from the value with a space.

The sign_posn variants are determined by the following values:

Value Description
0 Put parens around the value and the currency symbol.
1 Put the sign string in front of the currency symbol and value.
2 Put the sign string after the currency symbol and value.
3 Put the sign string directly in front of the currency symbol.
4 Put the sign string directly behind the currency symbol.

Return Value

Returns a pointer to the structure containing the locale information.

The program may not modify this structure.

Subsequent calls to localeconv() may overwrite this structure, as might calls to setlocale() with LC_ALL, LC_MONETARY, or LC_NUMERIC.


Here’s a program to print the locale information for the native locale.

#include <stdio.h>
#include <locale.h>
#include <limits.h>  // for CHAR_MAX

void print_grouping(char *mg)
    int done = 0;

    while (!done) {
        if (*mg == CHAR_MAX)
            printf("CHAR_MAX ");
            printf("%c ", *mg + '0');
        done = *mg == CHAR_MAX || *mg == 0;

int main(void)
    setlocale(LC_ALL, "");

    struct lconv *lc = localeconv();

    printf("mon_decimal_point : %s\n", lc->mon_decimal_point);
    printf("mon_thousands_sep : %s\n", lc->mon_thousands_sep);
    printf("mon_grouping      : ");
    printf("positive_sign     : %s\n", lc->positive_sign);
    printf("negative_sign     : %s\n", lc->negative_sign);
    printf("currency_symbol   : %s\n", lc->currency_symbol);
    printf("frac_digits       : %c\n", lc->frac_digits);
    printf("p_cs_precedes     : %c\n", lc->p_cs_precedes);
    printf("n_cs_precedes     : %c\n", lc->n_cs_precedes);
    printf("p_sep_by_space    : %c\n", lc->p_sep_by_space);
    printf("n_sep_by_space    : %c\n", lc->n_sep_by_space);
    printf("p_sign_posn       : %c\n", lc->p_sign_posn);
    printf("p_sign_posn       : %c\n", lc->p_sign_posn);
    printf("int_curr_symbol   : %s\n", lc->int_curr_symbol);
    printf("int_frac_digits   : %c\n", lc->int_frac_digits);
    printf("int_p_cs_precedes : %c\n", lc->int_p_cs_precedes);
    printf("int_n_cs_precedes : %c\n", lc->int_n_cs_precedes);
    printf("int_p_sep_by_space: %c\n", lc->int_p_sep_by_space);
    printf("int_n_sep_by_space: %c\n", lc->int_n_sep_by_space);
    printf("int_p_sign_posn   : %c\n", lc->int_p_sign_posn);
    printf("int_n_sign_posn   : %c\n", lc->int_n_sign_posn);

Output on my system:

mon_decimal_point : .
mon_thousands_sep : ,
mon_grouping      : 3 3 0 
positive_sign     : 
negative_sign     : -
currency_symbol   : $
frac_digits       : 2
p_cs_precedes     : 1
n_cs_precedes     : 1
p_sep_by_space    : 0
n_sep_by_space    : 0
p_sign_posn       : 1
p_sign_posn       : 1
int_curr_symbol   : USD 
int_frac_digits   : 2
int_p_cs_precedes : 1
int_n_cs_precedes : 1
int_p_sep_by_space: 1
int_n_sep_by_space: 1
int_p_sign_posn   : 1
int_n_sign_posn   : 1

See Also


Prev | Contents | Next