| Contents |

11 <limits.h> Giới Hạn Số

Lưu ý quan trọng: “minimum magnitude” (độ lớn tối thiểu) trong bảng bên dưới là giá trị tối thiểu mà spec yêu cầu. Rất có khả năng giá trị trên hệ thống xịn xò của bạn còn vượt xa những con số đó.

Macro Độ lớn tối thiểu Mô tả
CHAR_BIT 8 Số bit trong một byte
SCHAR_MIN -127 Giá trị nhỏ nhất của signed char
SCHAR_MAX 127 Giá trị lớn nhất của signed char
UCHAR_MAX 255 Giá trị lớn nhất của unsigned char19
CHAR_MIN 0 hoặc SCHAR_MIN Xem chi tiết bên dưới
CHAR_MAX SCHAR_MAX hoặc UCHAR_MAX Xem chi tiết bên dưới
MB_LEN_MAX 1 Số byte tối đa trong một ký tự multibyte ở bất cứ locale nào
SHRT_MIN -32767 Giá trị nhỏ nhất của short
SHRT_MAX 32767 Giá trị lớn nhất của short
USHRT_MAX 65535 Giá trị lớn nhất của unsigned short
INT_MIN -32767 Giá trị nhỏ nhất của int
INT_MAX 32767 Giá trị lớn nhất của int
UINT_MAX 65535 Giá trị lớn nhất của unsigned int
LONG_MIN -2147483647 Giá trị nhỏ nhất của long
LONG_MAX 2147483647 Giá trị lớn nhất của long
ULONG_MAX 4294967295 Giá trị lớn nhất của unsigned long
LLONG_MIN -9223372036854775807 Giá trị nhỏ nhất của long long
LLONG_MAX 9223372036854775807 Giá trị lớn nhất của long long
ULLONG_MAX 18446744073709551615 Giá trị lớn nhất của unsigned long long

11.1 CHAR_MINCHAR_MAX

Với CHAR_MINCHAR_MAX, mọi thứ phụ thuộc vào việc kiểu char mặc định trên hệ bạn là signed hay unsigned. Nhớ là C để tùy implementation quyết định chuyện đó chứ? Không nhớ? Thật đấy.

Vậy nếu nó là signed, CHAR_MINCHAR_MAX có giá trị giống như SCHAR_MINSCHAR_MAX.

Còn nếu nó là unsigned, CHAR_MINCHAR_MAX giống 0UCHAR_MAX.

Tiện thể: bạn có thể biết lúc runtime hệ có char signed hay unsigned bằng cách kiểm tra xem CHAR_MIN có bằng 0 không.

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

int main(void)
{
    printf("chars are %ssigned\n", CHAR_MIN == 0? "un": "");
}

Trên hệ của tôi, char là signed.

11.2 Chọn Kiểu Cho Đúng

Nếu bạn muốn siêu portable, hãy chọn một kiểu mà bảng bên trên đảm bảo ít nhất đủ to như bạn cần.

Nói vậy chứ, khá nhiều code—vì tốt hơn hoặc (khả năng cao hơn) tệ hơn—giả định rằng int là 32-bit, trong khi thực ra spec chỉ đảm bảo 16-bit thôi.

Nếu bạn cần kích thước bit được đảm bảo, xem các kiểu int_leastN_t trong <stdint.h>.

11.3 Còn Two’s Complement Thì Sao?

Nếu bạn tinh mắt và lại có hiểu biết sẵn về chủ đề này, bạn có thể đã nghĩ tôi viết sai giá trị nhỏ nhất của các macro bên trên.

short đi từ 32767 tới -32767? Chẳng phải nó phải tới -32768 à?”

Không, tôi viết đúng rồi. Spec liệt kê độ lớn tối thiểu cho các macro đó, và một số hệ thống cổ lỗ có thể đã dùng cách encode khác cho số signed mà chỉ đi xa được tới đó.

Hầu như mọi hệ thống hiện đại đều dùng Two’s Complement20 (bù hai) cho số signed, và với kiểu đó short sẽ đi từ 32767 tới -32768. Hệ của bạn chắc cũng vậy.

11.4 Chương Trình Demo

Đây là chương trình in ra giá trị các macro:

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

int main(void)
{
    printf("CHAR_BIT = %d\n", CHAR_BIT);
    printf("SCHAR_MIN = %d\n", SCHAR_MIN);
    printf("SCHAR_MAX = %d\n", SCHAR_MAX);
    printf("UCHAR_MAX = %d\n", UCHAR_MAX);
    printf("CHAR_MIN = %d\n", CHAR_MIN);
    printf("CHAR_MAX = %d\n", CHAR_MAX);
    printf("MB_LEN_MAX = %d\n", MB_LEN_MAX);
    printf("SHRT_MIN = %d\n", SHRT_MIN);
    printf("SHRT_MAX = %d\n", SHRT_MAX);
    printf("USHRT_MAX = %u\n", USHRT_MAX);
    printf("INT_MIN = %d\n", INT_MIN);
    printf("INT_MAX = %d\n", INT_MAX);
    printf("UINT_MAX = %u\n", UINT_MAX);
    printf("LONG_MIN = %ld\n", LONG_MIN);
    printf("LONG_MAX = %ld\n", LONG_MAX);
    printf("ULONG_MAX = %lu\n", ULONG_MAX);
    printf("LLONG_MIN = %lld\n", LLONG_MIN);
    printf("LLONG_MAX = %lld\n", LLONG_MAX);
    printf("ULLONG_MAX = %llu\n", ULLONG_MAX);
}

Trên hệ Intel 64-bit của tôi với clang, output là:

CHAR_BIT = 8
SCHAR_MIN = -128
SCHAR_MAX = 127
UCHAR_MAX = 255
CHAR_MIN = -128
CHAR_MAX = 127
MB_LEN_MAX = 6
SHRT_MIN = -32768
SHRT_MAX = 32767
USHRT_MAX = 65535
INT_MIN = -2147483648
INT_MAX = 2147483647
UINT_MAX = 4294967295
LONG_MIN = -9223372036854775808
LONG_MAX = 9223372036854775807
ULONG_MAX = 18446744073709551615
LLONG_MIN = -9223372036854775808
LLONG_MAX = 9223372036854775807
ULLONG_MAX = 18446744073709551615

Có vẻ hệ của tôi dùng encoding two’s-complement cho số signed, char là signed, và int là 32-bit.


| Contents |