Skip to content

C 标准库 - <locale.h>

概述

<locale.h> 头文件提供了本地化(localization)支持,允许程序适应不同的文化、语言和地区设置。本地化包括日期格式、时间格式、货币符号、数字格式等。

本地化类别

LC_ALL

所有本地化类别。

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

int main() {
    setlocale(LC_ALL, "");
    printf("当前本地化设置: %s\n", setlocale(LC_ALL, NULL));
    return 0;
}

LC_COLLATE

字符串比较和排序规则。

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

int main() {
    setlocale(LC_COLLATE, "en_US.UTF-8");
    printf("排序本地化: %s\n", setlocale(LC_COLLATE, NULL));
    
    char str1[] = "apple";
    char str2[] = "banana";
    
    int result = strcoll(str1, str2);
    printf("比较结果: %d\n", result);
    
    return 0;
}

LC_CTYPE

字符分类和转换。

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

int main() {
    setlocale(LC_CTYPE, "en_US.UTF-8");
    printf("字符本地化: %s\n", setlocale(LC_CTYPE, NULL));
    
    char c = 'A';
    printf("'%c' 是字母: %d\n", c, isalpha(c));
    
    return 0;
}

LC_MONETARY

货币格式。

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

int main() {
    setlocale(LC_MONETARY, "en_US.UTF-8");
    printf("货币本地化: %s\n", setlocale(LC_MONETARY, NULL));
    
    return 0;
}

LC_NUMERIC

数字格式(小数点、千位分隔符等)。

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

int main() {
    setlocale(LC_NUMERIC, "en_US.UTF-8");
    printf("数字本地化: %s\n", setlocale(LC_NUMERIC, NULL));
    
    double value = 1234567.89;
    printf("数字格式: %'.2f\n", value);
    
    return 0;
}

LC_TIME

时间和日期格式。

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

int main() {
    setlocale(LC_TIME, "en_US.UTF-8");
    printf("时间本地化: %s\n", setlocale(LC_TIME, NULL));
    
    time_t now = time(NULL);
    struct tm *tm = localtime(&now);
    
    char buffer[100];
    strftime(buffer, sizeof(buffer), "%A, %B %d, %Y", tm);
    printf("当前日期: %s\n", buffer);
    
    return 0;
}

本地化函数

setlocale()

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

设置或查询程序的本地化设置。

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

int main() {
    char *old_locale;
    
    old_locale = setlocale(LC_ALL, "en_US.UTF-8");
    printf("设置后的本地化: %s\n", setlocale(LC_ALL, NULL));
    
    old_locale = setlocale(LC_ALL, "zh_CN.UTF-8");
    printf("设置后的本地化: %s\n", setlocale(LC_ALL, NULL));
    
    return 0;
}

localeconv()

c
struct lconv *localeconv(void);

返回当前本地化的数字和货币格式信息。

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

int main() {
    setlocale(LC_ALL, "en_US.UTF-8");
    
    struct lconv *lc = localeconv();
    
    printf("小数点: %s\n", lc->decimal_point);
    printf("千位分隔符: %s\n", lc->thousands_sep);
    printf("分组: %s\n", lc->grouping);
    printf("货币符号: %s\n", lc->currency_symbol);
    printf("国际货币符号: %s\n", lc->int_curr_symbol);
    
    return 0;
}

lconv 结构体

c
struct lconv {
    char *decimal_point;
    char *thousands_sep;
    char *grouping;
    char *int_curr_symbol;
    char *currency_symbol;
    char *mon_decimal_point;
    char *mon_thousands_sep;
    char *mon_grouping;
    char *positive_sign;
    char *negative_sign;
    char int_frac_digits;
    char frac_digits;
    char p_cs_precedes;
    char p_sep_by_space;
    char n_cs_precedes;
    char n_sep_by_space;
    char p_sign_posn;
    char n_sign_posn;
};

实际应用示例

1. 显示所有本地化信息

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

void print_locale_info() {
    struct lconv *lc = localeconv();
    
    printf("=== 数字格式 ===\n");
    printf("小数点: '%s'\n", lc->decimal_point);
    printf("千位分隔符: '%s'\n", lc->thousands_sep);
    printf("分组: '%s'\n", lc->grouping);
    printf("\n");
    
    printf("=== 货币格式 ===\n");
    printf("货币符号: '%s'\n", lc->currency_symbol);
    printf("国际货币符号: '%s'\n", lc->int_curr_symbol);
    printf("货币小数点: '%s'\n", lc->mon_decimal_point);
    printf("货币千位分隔符: '%s'\n", lc->mon_thousands_sep);
    printf("货币分组: '%s'\n", lc->mon_grouping);
    printf("正号: '%s'\n", lc->positive_sign);
    printf("负号: '%s'\n", lc->negative_sign);
    printf("\n");
    
    printf("=== 货币位置 ===\n");
    printf("正数货币符号在前: %d\n", lc->p_cs_precedes);
    printf("正数货币符号用空格分隔: %d\n", lc->p_sep_by_space);
    printf("负数货币符号在前: %d\n", lc->n_cs_precedes);
    printf("负数货币符号用空格分隔: %d\n", lc->n_sep_by_space);
    printf("正数符号位置: %d\n", lc->p_sign_posn);
    printf("负数符号位置: %d\n", lc->n_sign_posn);
}

int main() {
    setlocale(LC_ALL, "en_US.UTF-8");
    printf("=== 美国本地化 ===\n");
    print_locale_info();
    
    setlocale(LC_ALL, "zh_CN.UTF-8");
    printf("\n=== 中国本地化 ===\n");
    print_locale_info();
    
    return 0;
}

2. 格式化货币

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

void format_currency(double amount) {
    struct lconv *lc = localeconv();
    char buffer[100];
    
    if (amount >= 0) {
        if (lc->p_cs_precedes) {
            if (lc->p_sep_by_space) {
                snprintf(buffer, sizeof(buffer), "%s %.2f", 
                        lc->currency_symbol, amount);
            } else {
                snprintf(buffer, sizeof(buffer), "%s%.2f", 
                        lc->currency_symbol, amount);
            }
        } else {
            if (lc->p_sep_by_space) {
                snprintf(buffer, sizeof(buffer), "%.2f %s", 
                        amount, lc->currency_symbol);
            } else {
                snprintf(buffer, sizeof(buffer), "%.2f%s", 
                        amount, lc->currency_symbol);
            }
        }
    } else {
        amount = -amount;
        if (lc->n_cs_precedes) {
            if (lc->n_sep_by_space) {
                snprintf(buffer, sizeof(buffer), "%s%s %.2f", 
                        lc->negative_sign, lc->currency_symbol, amount);
            } else {
                snprintf(buffer, sizeof(buffer), "%s%s%.2f", 
                        lc->negative_sign, lc->currency_symbol, amount);
            }
        } else {
            if (lc->n_sep_by_space) {
                snprintf(buffer, sizeof(buffer), "%s%.2f %s", 
                        lc->negative_sign, amount, lc->currency_symbol);
            } else {
                snprintf(buffer, sizeof(buffer), "%s%.2f%s", 
                        lc->negative_sign, amount, lc->currency_symbol);
            }
        }
    }
    
    printf("%s\n", buffer);
}

int main() {
    setlocale(LC_ALL, "en_US.UTF-8");
    printf("美国货币格式:\n");
    format_currency(1234.56);
    format_currency(-1234.56);
    
    setlocale(LC_ALL, "zh_CN.UTF-8");
    printf("\n中国货币格式:\n");
    format_currency(1234.56);
    format_currency(-1234.56);
    
    return 0;
}

3. 本地化字符串比较

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

void compare_strings(const char *str1, const char *str2) {
    int result = strcoll(str1, str2);
    
    if (result < 0) {
        printf("'%s' < '%s'\n", str1, str2);
    } else if (result > 0) {
        printf("'%s' > '%s'\n", str1, str2);
    } else {
        printf("'%s' == '%s'\n", str1, str2);
    }
}

int main() {
    setlocale(LC_COLLATE, "en_US.UTF-8");
    printf("英语排序:\n");
    compare_strings("apple", "banana");
    compare_strings("zebra", "apple");
    
    setlocale(LC_COLLATE, "zh_CN.UTF-8");
    printf("\n中文排序:\n");
    compare_strings("苹果", "香蕉");
    compare_strings("香蕉", "苹果");
    
    return 0;
}

4. 本地化日期时间

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

void print_localized_time() {
    time_t now = time(NULL);
    struct tm *tm = localtime(&now);
    
    char buffer[100];
    
    strftime(buffer, sizeof(buffer), "%A, %B %d, %Y", tm);
    printf("日期: %s\n", buffer);
    
    strftime(buffer, sizeof(buffer), "%H:%M:%S", tm);
    printf("时间: %s\n", buffer);
    
    strftime(buffer, sizeof(buffer), "%x", tm);
    printf("短日期: %s\n", buffer);
    
    strftime(buffer, sizeof(buffer), "%X", tm);
    printf("短时间: %s\n", buffer);
}

int main() {
    setlocale(LC_TIME, "en_US.UTF-8");
    printf("英语时间格式:\n");
    print_localized_time();
    
    setlocale(LC_TIME, "zh_CN.UTF-8");
    printf("\n中文时间格式:\n");
    print_localized_time();
    
    return 0;
}

5. 本地化数字格式

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

void print_localized_number(double value) {
    printf("数字: %'.2f\n", value);
}

int main() {
    double value = 1234567.89;
    
    setlocale(LC_NUMERIC, "en_US.UTF-8");
    printf("美国数字格式:\n");
    print_localized_number(value);
    
    setlocale(LC_NUMERIC, "de_DE.UTF-8");
    printf("\n德国数字格式:\n");
    print_localized_number(value);
    
    setlocale(LC_NUMERIC, "zh_CN.UTF-8");
    printf("\n中国数字格式:\n");
    print_localized_number(value);
    
    return 0;
}

6. 检查可用本地化

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

void test_locale(const char *locale) {
    char *result = setlocale(LC_ALL, locale);
    if (result != NULL) {
        printf("本地化 '%s' 可用: %s\n", locale, result);
    } else {
        printf("本地化 '%s' 不可用\n", locale);
    }
}

int main() {
    const char *locales[] = {
        "en_US.UTF-8",
        "en_US",
        "zh_CN.UTF-8",
        "zh_CN",
        "de_DE.UTF-8",
        "fr_FR.UTF-8",
        "ja_JP.UTF-8",
        NULL
    };
    
    for (int i = 0; locales[i] != NULL; i++) {
        test_locale(locales[i]);
    }
    
    return 0;
}

7. 切换本地化

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

void switch_locale(int category, const char *locale) {
    char *old_locale = setlocale(category, locale);
    if (old_locale != NULL) {
        printf("切换到 '%s': 成功\n", locale);
    } else {
        printf("切换到 '%s': 失败\n", locale);
    }
}

int main() {
    printf("=== 切换本地化 ===\n");
    
    switch_locale(LC_ALL, "en_US.UTF-8");
    switch_locale(LC_ALL, "zh_CN.UTF-8");
    switch_locale(LC_ALL, "de_DE.UTF-8");
    
    printf("\n=== 恢复默认本地化 ===\n");
    setlocale(LC_ALL, "C");
    printf("当前本地化: %s\n", setlocale(LC_ALL, NULL));
    
    return 0;
}

本地化注意事项

1. 线程安全

setlocale() 函数会影响整个程序,不是线程安全的。在多线程程序中使用时需要小心。

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

void* thread_func(void* arg) {
    int thread_id = *(int*)arg;
    
    setlocale(LC_ALL, "en_US.UTF-8");
    printf("线程 %d: %s\n", thread_id, setlocale(LC_ALL, NULL));
    
    return NULL;
}

int main() {
    pthread_t threads[3];
    int ids[3] = {1, 2, 3};
    
    for (int i = 0; i < 3; i++) {
        pthread_create(&threads[i], NULL, thread_func, &ids[i]);
    }
    
    for (int i = 0; i < 3; i++) {
        pthread_join(threads[i], NULL);
    }
    
    return 0;
}

2. 本地化名称

本地化名称的格式通常为 language_territory.encoding,例如:

  • en_US.UTF-8 - 美国英语,UTF-8 编码
  • zh_CN.UTF-8 - 中国中文,UTF-8 编码
  • de_DE.UTF-8 - 德国德语,UTF-8 编码

3. 默认本地化

使用空字符串 "" 作为 locale 参数会使用系统的默认本地化设置。

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

int main() {
    setlocale(LC_ALL, "");
    printf("系统默认本地化: %s\n", setlocale(LC_ALL, NULL));
    
    return 0;
}

总结

<locale.h> 提供的本地化功能对于开发国际化的应用程序非常重要。通过使用本地化功能,开发者可以:

  1. 适应不同地区 - 根据用户的地区设置调整程序的显示格式
  2. 提高用户体验 - 使用用户熟悉的日期、时间、货币和数字格式
  3. 支持多语言 - 支持不同语言的字符串排序和比较
  4. 增强程序可用性 - 使程序更容易被不同文化背景的用户接受

记住:

  • 本地化设置会影响整个程序
  • 在多线程环境中要小心使用
  • 使用系统默认本地化时使用空字符串
  • 不同的系统可能支持不同的本地化设置