C Standard Library locale.h

Beginner
⏱️ 12 min read
📚 Updated: Jul 2026
🎯 5 Examples
<locale.h>

What You’ll Learn

The <locale.h> header controls locale—the cultural rules for formatting numbers, money, dates, and sorting text. With setlocale and localeconv, your program can follow the user’s regional settings instead of always using the plain "C" locale.

01

setlocale

Set/query.

02

LC_ALL

Everything.

03

LC_NUMERIC

Numbers.

04

localeconv

lconv info.

05

"C"

Default.

06

LC_TIME

Dates.

Definition and Usage

A locale bundles conventions: which character is the decimal point, how dates are written, how strings sort, and how ctype classifies letters. At startup, C programs use the "C" locale unless you call setlocale.

setlocale(int category, const char *locale) changes one category or all of them. Pass NULL as the second argument to query the current setting without changing it. On success it returns a string naming the locale; on failure it returns NULL.

💡
Beginner Tip

The old reference used printf("%'f", ...) for thousands separators—that is a GNU extension, not standard C. Use localeconv() for portable formatting, or document that your program requires GNU libc.

📝 Syntax

Include the header:

C
#include <locale.h>

Category macros

  • LC_ALL — all categories together.
  • LC_COLLATE — string collation (strcoll, strxfrm).
  • LC_CTYPE — character classification (isalpha, toupper).
  • LC_MONETARY — currency formatting.
  • LC_NUMERIC — decimal point and thousands separator for numbers.
  • LC_TIME — date and time format (strftime).

Functions

C
char *setlocale(int category, const char *locale);
struct lconv *localeconv(void);

Common locale strings

  • "C" — portable default (dot decimal, predictable sorting).
  • "" — use environment (LANG, LC_* variables).
  • "en_US.UTF-8" — US English with UTF-8 (if installed on the system).
  • "de_DE.UTF-8" — German locale example (availability varies).

Key struct lconv fields

  • decimal_point — character between integer and fraction (often "." or ",").
  • thousands_sep — grouping separator (often "," or ".").
  • grouping — rules for digit groups.
  • currency_symbol, mon_decimal_point — monetary formatting.

Headers and linking

  • #include <locale.h> — no special link flag.
  • Date examples: #include <time.h> for strftime.
  • Compile: gcc program.c -std=c11 -o program

⚡ Quick Reference

CallPurposeExample
setlocale(LC_ALL, "C")Reset to portable localePredictable numbers
setlocale(LC_ALL, "")Use user environmentDesktop apps
setlocale(cat, NULL)Query current localeSave before change
localeconv()Numeric/monetary detailslc->decimal_point
LC_NUMERICNumbers onlyLeave time locale alone
Check
if (!setlocale(...))

Handle failure

Query
setlocale(LC_ALL, NULL)

Current name

Decimal
localeconv()->decimal_point

Separator char

Restore
setlocale(LC_ALL, saved)

Undo change

Examples Gallery

Compile with gcc file.c -std=c11 -o out. Locale names and output vary by OS. Examples use "C" where portability matters; regional locales may need to be installed on your system.

📚 Getting Started

Read formatting rules and set locale safely.

Example 1 — Read Formatting with localeconv

Portable replacement for the reference example—no GNU %'f extension.

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

int main(void) {
    const struct lconv *lc;

    if (setlocale(LC_ALL, "C") == NULL) {
        printf("Failed to set C locale\n");
        return 1;
    }

    lc = localeconv();

    printf("Decimal point: '%s'\n", lc->decimal_point);
    printf("Thousands sep: '%s'\n",
           lc->thousands_sep[0] ? lc->thousands_sep : "(none)");

  /* printf uses locale for some conversions; C locale uses '.' */
    printf("Number: %.2f\n", 1234567.89);

    return 0;
}

How It Works

localeconv returns pointers to strings describing separators. In the "C" locale the decimal point is . and there is no thousands separator. Standard printf does not insert thousands commas without extensions.

Example 2 — Always Check setlocale Return Value

Trying an unavailable locale must not be ignored.

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

int main(void) {
    char *result = setlocale(LC_ALL, "xx_YY.UTF-8");

    if (result == NULL) {
        printf("Locale not available — falling back to C\n");
        setlocale(LC_ALL, "C");
    } else {
        printf("Locale set to: %s\n", result);
    }

    printf("Current locale: %s\n", setlocale(LC_ALL, NULL));

    return 0;
}

How It Works

setlocale returns NULL when the requested locale is not installed. Fall back to "C" for predictable behavior. Use setlocale(LC_ALL, NULL) to read the active locale name.

📈 Practical Patterns

Change one category, format dates, and restore settings.

Example 3 — Change Only LC_NUMERIC

Adjust number formatting without affecting date or collation settings.

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

int main(void) {
    setlocale(LC_ALL, "C");
    printf("C locale:     %.2f\n", 3.14);

    if (setlocale(LC_NUMERIC, "en_US.UTF-8") != NULL) {
        printf("en_US numeric: %.2f\n", 3.14);
        printf("Decimal point: %s\n", localeconv()->decimal_point);
    } else {
        printf("en_US.UTF-8 not installed on this system\n");
    }

    return 0;
}

How It Works

LC_NUMERIC limits the change to number formatting. Some European locales use , as the decimal separator—try de_DE.UTF-8 on Linux if installed to see 3,14 style output from printf.

Example 4 — LC_TIME and strftime

Locale affects how dates and times are printed.

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

void print_date(const char *locale_name) {
    time_t now = time(NULL);
    struct tm *tm_info = localtime(&now);
    char buf[64];

    setlocale(LC_TIME, locale_name);
    strftime(buf, sizeof(buf), "%A, %d %B %Y", tm_info);
    printf("LC_TIME=%s: %s\n", locale_name, buf);
}

int main(void) {
    print_date("C");
    if (setlocale(LC_TIME, "en_US.UTF-8") != NULL) {
        print_date("en_US.UTF-8");
    }
    return 0;
}

How It Works

strftime with %A (weekday) and %B (month) uses LC_TIME. In locales like de_DE.UTF-8, month and day names appear in German. Output depends on installed locales and the current date.

Example 5 — Save and Restore Locale

Temporarily switch locale, then put it back to avoid surprising other code.

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

int main(void) {
    char saved[64];
    const char *cur = setlocale(LC_ALL, NULL);

    if (cur != NULL) {
        strncpy(saved, cur, sizeof(saved) - 1);
        saved[sizeof(saved) - 1] = '\0';
    }

    printf("Before: %s\n", setlocale(LC_ALL, NULL));

    setlocale(LC_ALL, "C");
    printf("During: %s (printing %.2f)\n", setlocale(LC_ALL, NULL), 1.5);

    setlocale(LC_ALL, saved);
    printf("After restore: %s\n", setlocale(LC_ALL, NULL));

    return 0;
}

How It Works

Save the locale name before changing it. Libraries and other modules may assume the original locale. Copy the string because subsequent setlocale calls may invalidate the old pointer.

🚀 Common Use Cases

  • Desktop utilitiessetlocale(LC_ALL, "") to match the user’s OS settings.
  • Report generators — locale-aware dates with strftime and LC_TIME.
  • Financial outputlocaleconv currency fields for invoices.
  • Sorting namesLC_COLLATE with strcoll for dictionary order.
  • Parsers — read decimal_point before parsing user numbers.
  • Servers — keep "C" locale for logs; localize only UI layers.

🧠 How locale.h Works

1

Choose category

LC_ALL for everything, or LC_NUMERIC / LC_TIME alone.

Category
2

Call setlocale

Pass locale name or "" for environment. Check for NULL.

Activate
3

Library functions adapt

printf, strftime, isalpha, strcoll follow the locale.

Effect
=

Localized output

Numbers, dates, and sort order match regional expectations.

📝 Notes

  • Programs start in the "C" locale unless the environment or your code changes it.
  • Locale names are platform-specific; en_US.UTF-8 on Linux may differ on Windows (English_United States.utf8).
  • setlocale is not thread-safe—avoid changing locale in multithreaded servers casually.
  • localeconv returns a static struct; copy strings if you call setlocale again.
  • Changing LC_CTYPE affects <ctype.h> functions for non-ASCII letters.
  • For full Unicode/i18n, many projects use ICU or similar libraries beyond standard C.

⚡ Optimization

Keep the default "C" locale in performance-critical paths. Locale-aware collation and formatting are slower than byte-wise compares and fixed printf formats. Change locale only at UI boundaries or when generating user-facing output.

Conclusion

<locale.h> lets C programs respect cultural conventions for numbers, money, dates, and text ordering. Use setlocale with care, check return values, and read details with localeconv.

For predictable behavior in libraries and servers, default to "C". For user-facing apps, setlocale(LC_ALL, "") picks up the environment—when that locale is available.

💡 Best Practices

✅ Do

  • Check setlocale for NULL and fall back to "C"
  • Save and restore locale around temporary changes
  • Use LC_NUMERIC / LC_TIME when you need only one category
  • Use localeconv for portable separator characters
  • Keep servers and libraries on "C" unless required

❌ Don’t

  • Assume %'f works outside GNU systems
  • Change locale in one thread without protecting others
  • Ignore failed setlocale calls
  • Store pointers from localeconv across setlocale calls
  • Assume every locale name works on every OS

Key Takeaways

Knowledge Unlocked

Five things to remember about locale.h

Localization in C, explained simply.

5
Core concepts
📚 02

"C"

Portable.

Default
📈 03

localeconv

Separators.

lconv
📄 04

LC_*

Categories.

Granular
🌐 05

Threads

Not safe.

Caution

❓ Frequently Asked Questions

locale.h provides setlocale() to change or query cultural conventions (number format, date format, collation, character classes) and localeconv() to read numeric and monetary formatting details. It helps programs adapt output to a region or language.
It sets the entire locale from environment variables such as LANG and LC_* (e.g. LC_NUMERIC). An empty string means 'use the user's environment.' On success it returns a locale name string; on failure it returns NULL.
The default portable locale, often selected with setlocale(LC_ALL, "C"). Numbers use a dot as the decimal point, sorting is byte-based, and behavior is predictable across platforms. Programs start in the C locale unless changed.
No. setlocale modifies global locale state and is not thread-safe in standard C. Multithreaded programs should avoid changing locale in one thread while others use locale-sensitive functions, or use platform-specific per-thread locale APIs.
localeconv() returns a pointer to struct lconv with fields like decimal_point, thousands_sep, currency_symbol, and grouping rules for the current locale. The structure is static—copy strings if you need them after another locale change.
The ' flag in %'f is a GNU extension, not standard C. Portable code should read thousands_sep from localeconv() and format numbers manually, or use higher-level libraries. Do not rely on %'f for cross-platform programs.
Did you know?

The "C" locale is not “American English”—it is a minimal, portable convention designed for consistent program behavior. Real-world localization often needs installed OS locale data, and embedded systems may only support "C". That is why robust apps check setlocale and ship fallbacks.

Explore C Standard Library Headers

Continue with math.h or browse the library index.

Standard Library Index →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

5 people found this page helpful