Skip to content

C 标准库 - <limits.h>

概述

<limits.h> 头文件定义了各种整数类型的限制值,包括最小值、最大值和位数等信息。这些宏帮助开发者了解整数类型的范围,避免溢出和其他相关问题。

整数类型

C 语言支持多种整数类型:

  • char - 字符类型
  • signed char - 有符号字符
  • unsigned char - 无符号字符
  • short - 短整型
  • unsigned short - 无符号短整型
  • int - 整型
  • unsigned int - 无符号整型
  • long - 长整型
  • unsigned long - 无符号长整型
  • long long - 长长整型(C99)
  • unsigned long long - 无符号长长整型(C99)

字符类型限制

CHAR_BIT

char 类型的位数(通常为 8)。

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

int main() {
    printf("char 位数: %d\n", CHAR_BIT);
    return 0;
}

CHAR_MIN

char 类型的最小值。

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

int main() {
    printf("char 最小值: %d\n", CHAR_MIN);
    return 0;
}

CHAR_MAX

char 类型的最大值。

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

int main() {
    printf("char 最大值: %d\n", CHAR_MAX);
    return 0;
}

SCHAR_MIN, SCHAR_MAX

signed char 类型的最小值和最大值。

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

int main() {
    printf("signed char 最小值: %d\n", SCHAR_MIN);
    printf("signed char 最大值: %d\n", SCHAR_MAX);
    return 0;
}

UCHAR_MAX

unsigned char 类型的最大值。

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

int main() {
    printf("unsigned char 最大值: %u\n", UCHAR_MAX);
    return 0;
}

短整型限制

SHRT_MIN, SHRT_MAX

short 类型的最小值和最大值。

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

int main() {
    printf("short 最小值: %d\n", SHRT_MIN);
    printf("short 最大值: %d\n", SHRT_MAX);
    return 0;
}

USHRT_MAX

unsigned short 类型的最大值。

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

int main() {
    printf("unsigned short 最大值: %u\n", USHRT_MAX);
    return 0;
}

整型限制

INT_MIN, INT_MAX

int 类型的最小值和最大值。

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

int main() {
    printf("int 最小值: %d\n", INT_MIN);
    printf("int 最大值: %d\n", INT_MAX);
    return 0;
}

UINT_MAX

unsigned int 类型的最大值。

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

int main() {
    printf("unsigned int 最大值: %u\n", UINT_MAX);
    return 0;
}

长整型限制

LONG_MIN, LONG_MAX

long 类型的最小值和最大值。

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

int main() {
    printf("long 最小值: %ld\n", LONG_MIN);
    printf("long 最大值: %ld\n", LONG_MAX);
    return 0;
}

ULONG_MAX

unsigned long 类型的最大值。

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

int main() {
    printf("unsigned long 最大值: %lu\n", ULONG_MAX);
    return 0;
}

长长整型限制(C99)

LLONG_MIN, LLONG_MAX

long long 类型的最小值和最大值。

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

int main() {
    printf("long long 最小值: %lld\n", LLONG_MIN);
    printf("long long 最大值: %lld\n", LLONG_MAX);
    return 0;
}

ULLONG_MAX

unsigned long long 类型的最大值。

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

int main() {
    printf("unsigned long long 最大值: %llu\n", ULLONG_MAX);
    return 0;
}

其他限制

MB_LEN_MAX

多字节字符的最大字节数。

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

int main() {
    printf("多字节字符最大字节数: %d\n", MB_LEN_MAX);
    return 0;
}

实际应用示例

1. 显示所有整数类型限制

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

void print_all_limits() {
    printf("=== 字符类型 ===\n");
    printf("CHAR_BIT: %d\n", CHAR_BIT);
    printf("CHAR_MIN: %d\n", CHAR_MIN);
    printf("CHAR_MAX: %d\n", CHAR_MAX);
    printf("SCHAR_MIN: %d\n", SCHAR_MIN);
    printf("SCHAR_MAX: %d\n", SCHAR_MAX);
    printf("UCHAR_MAX: %u\n", UCHAR_MAX);
    printf("\n");
    
    printf("=== 短整型 ===\n");
    printf("SHRT_MIN: %d\n", SHRT_MIN);
    printf("SHRT_MAX: %d\n", SHRT_MAX);
    printf("USHRT_MAX: %u\n", USHRT_MAX);
    printf("\n");
    
    printf("=== 整型 ===\n");
    printf("INT_MIN: %d\n", INT_MIN);
    printf("INT_MAX: %d\n", INT_MAX);
    printf("UINT_MAX: %u\n", UINT_MAX);
    printf("\n");
    
    printf("=== 长整型 ===\n");
    printf("LONG_MIN: %ld\n", LONG_MIN);
    printf("LONG_MAX: %ld\n", LONG_MAX);
    printf("ULONG_MAX: %lu\n", ULONG_MAX);
    printf("\n");
    
    printf("=== 长长整型 ===\n");
    printf("LLONG_MIN: %lld\n", LLONG_MIN);
    printf("LLONG_MAX: %lld\n", LLONG_MAX);
    printf("ULLONG_MAX: %llu\n", ULLONG_MAX);
    printf("\n");
    
    printf("=== 其他 ===\n");
    printf("MB_LEN_MAX: %d\n", MB_LEN_MAX);
}

int main() {
    print_all_limits();
    return 0;
}

2. 安全的整数加法

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

int safe_add(int a, int b) {
    if (a > 0 && b > INT_MAX - a) {
        printf("警告: 加法溢出\n");
        return INT_MAX;
    }
    if (a < 0 && b < INT_MIN - a) {
        printf("警告: 加法下溢\n");
        return INT_MIN;
    }
    return a + b;
}

int main() {
    int result1 = safe_add(1000, 2000);
    printf("1000 + 2000 = %d\n", result1);
    
    int result2 = safe_add(INT_MAX, 1);
    printf("INT_MAX + 1 = %d\n", result2);
    
    return 0;
}

3. 安全的整数乘法

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

int safe_multiply(int a, int b) {
    if (a > 0) {
        if (b > INT_MAX / a) {
            printf("警告: 乘法溢出\n");
            return INT_MAX;
        }
        if (b < INT_MIN / a) {
            printf("警告: 乘法下溢\n");
            return INT_MIN;
        }
    } else if (a < 0) {
        if (b < INT_MAX / a) {
            printf("警告: 乘法溢出\n");
            return INT_MAX;
        }
        if (b > INT_MIN / a) {
            printf("警告: 乘法下溢\n");
            return INT_MIN;
        }
    }
    return a * b;
}

int main() {
    int result1 = safe_multiply(1000, 2000);
    printf("1000 * 2000 = %d\n", result1);
    
    int result2 = safe_multiply(INT_MAX, 2);
    printf("INT_MAX * 2 = %d\n", result2);
    
    return 0;
}

4. 检查整数范围

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

int is_in_int_range(long value) {
    return value >= INT_MIN && value <= INT_MAX;
}

int is_in_unsigned_int_range(long value) {
    return value >= 0 && value <= UINT_MAX;
}

int main() {
    long values[] = {100, -100, INT_MAX + 1L, INT_MIN - 1L, 0};
    int count = sizeof(values) / sizeof(values[0]);
    
    for (int i = 0; i < count; i++) {
        long value = values[i];
        printf("%ld 在 int 范围内: %d\n", value, is_in_int_range(value));
        printf("%ld 在 unsigned int 范围内: %d\n", value, is_in_unsigned_int_range(value));
        printf("\n");
    }
    
    return 0;
}

5. 选择合适的整数类型

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

const char* get_min_type(long long value) {
    if (value >= SCHAR_MIN && value <= SCHAR_MAX) {
        return "signed char";
    } else if (value >= 0 && value <= UCHAR_MAX) {
        return "unsigned char";
    } else if (value >= SHRT_MIN && value <= SHRT_MAX) {
        return "short";
    } else if (value >= 0 && value <= USHRT_MAX) {
        return "unsigned short";
    } else if (value >= INT_MIN && value <= INT_MAX) {
        return "int";
    } else if (value >= 0 && value <= UINT_MAX) {
        return "unsigned int";
    } else if (value >= LONG_MIN && value <= LONG_MAX) {
        return "long";
    } else if (value >= 0 && value <= ULONG_MAX) {
        return "unsigned long";
    } else if (value >= LLONG_MIN && value <= LLONG_MAX) {
        return "long long";
    } else {
        return "超出范围";
    }
}

int main() {
    long long values[] = {10, 1000, 100000, INT_MAX + 1LL, LLONG_MAX};
    int count = sizeof(values) / sizeof(values[0]);
    
    for (int i = 0; i < count; i++) {
        long long value = values[i];
        printf("值 %lld 的最小类型: %s\n", value, get_min_type(value));
    }
    
    return 0;
}

6. 整数溢出检测

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

int add_with_overflow_check(int a, int b, int* result) {
    if (a > 0 && b > INT_MAX - a) {
        return 1;
    }
    if (a < 0 && b < INT_MIN - a) {
        return 1;
    }
    *result = a + b;
    return 0;
}

int multiply_with_overflow_check(int a, int b, int* result) {
    if (a > 0) {
        if (b > INT_MAX / a) return 1;
        if (b < INT_MIN / a) return 1;
    } else if (a < 0) {
        if (b < INT_MAX / a) return 1;
        if (b > INT_MIN / a) return 1;
    } else if (a == 0) {
        *result = 0;
        return 0;
    }
    *result = a * b;
    return 0;
}

int main() {
    int result;
    
    if (add_with_overflow_check(INT_MAX, 1, &result)) {
        printf("加法溢出\n");
    } else {
        printf("加法结果: %d\n", result);
    }
    
    if (multiply_with_overflow_check(INT_MAX, 2, &result)) {
        printf("乘法溢出\n");
    } else {
        printf("乘法结果: %d\n", result);
    }
    
    return 0;
}

7. 整数类型大小和范围

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

void print_type_info(const char* type_name, size_t size, 
                     long long min_value, unsigned long long max_value) {
    printf("%-15s 大小: %2zu 字节, 最小值: %20lld, 最大值: %20llu\n",
           type_name, size, min_value, max_value);
}

int main() {
    printf("=== 整数类型信息 ===\n");
    
    print_type_info("char", sizeof(char), CHAR_MIN, CHAR_MAX);
    print_type_info("signed char", sizeof(signed char), SCHAR_MIN, SCHAR_MAX);
    print_type_info("unsigned char", sizeof(unsigned char), 0, UCHAR_MAX);
    
    print_type_info("short", sizeof(short), SHRT_MIN, SHRT_MAX);
    print_type_info("unsigned short", sizeof(unsigned short), 0, USHRT_MAX);
    
    print_type_info("int", sizeof(int), INT_MIN, INT_MAX);
    print_type_info("unsigned int", sizeof(unsigned int), 0, UINT_MAX);
    
    print_type_info("long", sizeof(long), LONG_MIN, LONG_MAX);
    print_type_info("unsigned long", sizeof(unsigned long), 0, ULONG_MAX);
    
    print_type_info("long long", sizeof(long long), LLONG_MIN, LLONG_MAX);
    print_type_info("unsigned long long", sizeof(unsigned long long), 0, ULLONG_MAX);
    
    return 0;
}

整数溢出注意事项

1. 有符号整数溢出

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

int main() {
    int a = INT_MAX;
    int b = a + 1;
    
    printf("INT_MAX: %d\n", a);
    printf("INT_MAX + 1: %d\n", b);
    printf("INT_MIN: %d\n", INT_MIN);
    
    return 0;
}

2. 无符号整数溢出

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

int main() {
    unsigned int a = UINT_MAX;
    unsigned int b = a + 1;
    
    printf("UINT_MAX: %u\n", a);
    printf("UINT_MAX + 1: %u\n", b);
    printf("0: %u\n", 0U);
    
    return 0;
}

3. 混合运算

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

int main() {
    int a = -1;
    unsigned int b = 1;
    
    printf("-1 + 1 (int): %d\n", a + (int)b);
    printf("-1 + 1 (unsigned): %u\n", (unsigned)a + b);
    
    return 0;
}

总结

<limits.h> 提供的整数限制宏对于编写安全、可靠的程序非常重要。通过了解这些限制,开发者可以:

  1. 避免整数溢出 - 在进行算术运算前检查是否会溢出
  2. 选择合适的类型 - 根据数值范围选择最合适的整数类型
  3. 编写可移植代码 - 使用标准宏而不是硬编码的值
  4. 理解类型行为 - 了解不同整数类型的范围和特性

记住:

  • 有符号整数溢出是未定义行为
  • 无符号整数溢出是定义的行为(模运算)
  • 使用 <limits.h> 中的宏而不是硬编码的值
  • 在进行算术运算前检查是否会溢出