giá trị tối thiểu và tối đa của kiểu dữ liệu trong C


76

Hàm để xác định giá trị tối thiểu và tối đa có thể có của các kiểu dữ liệu (tức là int, char.etc) trong C là gì?

Câu trả lời:


92

Bạn sẽ muốn sử dụng limits.hcung cấp các hằng số sau (theo tham chiếu được liên kết):

Trường hợp U*_MINbị bỏ qua vì những lý do rõ ràng (bất kỳ kiểu không dấu nào có giá trị nhỏ nhất là 0).

Tương tự, float.hcung cấp các giới hạn cho floatdoublecác loại:

Bạn nên đọc kỹ bài viết về floats.hmặc dù floatdoublecó thể giữ các giá trị tối thiểu và tối đa được quy định nhưng độ chính xác mà mỗi loại có thể đại diện cho dữ liệu có thể không khớp với những gì bạn đang cố gắng lưu trữ. Đặc biệt, rất khó để lưu trữ các số đặc biệt lớn với các phân số cực nhỏ kèm theo. Vì vậy, float.hcung cấp một số hằng số khác giúp bạn xác định xem trên thực tế, một floathoặc một doublecó thể đại diện cho một số cụ thể.


2
giá trị tối thiểu và giá trị lớn nhất của float là bao nhiêu?
SuperString

3
SIZE_MAX(kích thước tối đa của a size_t) là một kích thước hữu ích khác.
caf

size_t maxSize = SIZE_MAX;
Joey van Hummel

@MartinBeckett không theo tệp tiêu đề, hoặc kỷ niệm của tôi khi viết điều này bằng C? FLT_MIN xấp xỉ 0, không?
Adam

Từ chối vì câu trả lời là - đơn giản - sai. Câu hỏi yêu cầu giá trị tối thiểu và tối đa, và tệp tiêu đề chỉ chứa câu trả lời cho giá trị tối đa. Giá trị tối thiểu phải được tính toán (rất vui khi thay đổi phiếu bầu của tôi nếu ai đó đi cùng và sửa chữa tôi, nhưng sự hiểu biết / ghi nhớ của tôi là theo nhận xét của @ JohnMudd). "FLT_MIN = giá trị tối thiểu của một số float" như được viết trong câu trả lời này là hoàn toàn SAI.
Adam

33

"Nhưng glyph", tôi nghe thấy bạn hỏi, "điều gì sẽ xảy ra nếu tôi phải xác định giá trị lớn nhất cho một loại không trong suốt mà giá trị tối đa cuối cùng có thể thay đổi?" Bạn có thể tiếp tục: "Điều gì sẽ xảy ra nếu đó là một typedef trong thư viện mà tôi không kiểm soát?"

Tôi rất vui vì bạn đã hỏi, vì tôi vừa dành vài giờ để tìm ra giải pháp (mà sau đó tôi phải vứt bỏ, vì nó không giải quyết được vấn đề thực tế của tôi).

Bạn có thể sử dụng maxofmacro tiện dụng này để xác định kích thước của bất kỳ kiểu số nguyên hợp lệ nào.

Bạn có thể sử dụng nó như vậy:

Nếu muốn, bạn có thể ném '(t)' lên phía trước các macro đó để chúng cung cấp cho bạn kết quả về loại mà bạn đang hỏi và bạn không phải thực hiện truyền để tránh cảnh báo.


Sẽ không ~((t) 0)hoạt động cho tối đa không dấu? (nó không, nhưng tôi không chắc tại sao được nêu ra).
Gauthier

Cảm ơn vì thông tin về phát hiện ký. Tôi sẽ cập nhật câu trả lời.
Glyph

1
Tất cả các hằng số 8ULL đó có lẽ phải là CHAR_BIT để thay thế.
jschultz410

umaxof (t) có thể được viết dễ dàng hơn nhiều là ((t) -1) hoặc (~ (t) 0), cả hai đều được đảm bảo hoạt động theo tiêu chuẩn C. smaxof (t) có thể được viết ((t) ~ (1ULL << (sizeof (t) * CHARBIT - 1))). Mức tối thiểu đã ký phức tạp hơn rất nhiều.
jschultz410

Đồng ý với maxof có điều kiện bằng cách sử dụng macro chính xác tùy thuộc vào điều hành!
jschultz410

7

Giá trị lớn nhất của bất kỳ loại tích phân không dấu nào :

  • ((t)~(t)0) // Biểu thức chung sẽ hoạt động trong hầu hết mọi trường hợp.

  • (~(t)0)// Nếu bạn biết loại của bạn tcó kích thước bằng hoặc lớn hơn unsigned int. (Diễn viên này buộc phải thăng hạng.)

  • ((t)~0U)// Nếu bạn biết loại của bạn tcó kích thước nhỏ hơn unsigned int. (Loại giảm hạng truyền này sau khi unsigned intbiểu thức -type ~0Uđược đánh giá.)

Tối đa giá trị của bất kỳ kiểu không thể thiếu:

  • Nếu bạn có kiểu biến thể không dấu t, ((t)(((unsigned t)~(unsigned t)0)>>1))sẽ cung cấp cho bạn kết quả nhanh nhất mà bạn cần.

  • Nếu không, hãy sử dụng cái này (nhờ @ vinc17 gợi ý): (((1ULL<<(sizeof(t)*CHAR_BIT-2))-1)*2+1)

Tối thiểu giá trị của bất kỳ kiểu không thể thiếu:

Bạn phải biết đại diện số đã ký trên máy của bạn. Hầu hết các máy sử dụng phần bổ sung của 2 và vì vậy -(((1ULL<<(sizeof(t)*CHAR_BIT-2))-1)*2+1)-1sẽ phù hợp với bạn.

Để phát hiện xem máy của bạn có sử dụng phần bổ sung của 2 hay không, hãy phát hiện xem có (~(t)0U)(t)(-1)đại diện cho cùng một thứ hay không.

Vì vậy, kết hợp với trên:

sẽ cung cấp cho bạn giá trị nhỏ nhất của bất kỳ loại tích phân có dấu nào.

Ví dụ: Giá trị tối đa của size_t(hay còn gọi là SIZE_MAXmacro) có thể được xác định là (~(size_t)0). Mã nguồn nhân Linux xác định SIZE_MAXmacro theo cách này.

Tuy nhiên, có một lưu ý : Tất cả các biểu thức này đều sử dụng kiểu ép kiểu hoặc sizeoftoán tử và vì vậy không có điều nào trong số này sẽ hoạt động trong các điều kiện tiền xử lý ( #if... #elif... #endifvà tương tự).

(Đã cập nhật câu trả lời cho các đề xuất bổ sung từ @chux và @ vinc17. Cảm ơn cả hai.)


Lưu ý rằng unsigned long longcó thể không phải là kiểu số nguyên lớn nhất; uintmax_tsẽ tốt hơn nhưng thậm chí không phải lúc nào cũng là kiểu số nguyên lớn nhất trong thực tế (xem GCC's __int128). Tôi đã đưa ra một giải pháp di động hơn cho tối đa các loại có chữ ký trong câu trả lời của mình. Sau đó, mức tối thiểu có thể được suy ra từ nó như bạn đã làm. Liên quan đến các điều kiện của bộ tiền xử lý, sizeofcũng không thể được sử dụng vì tiền xử lý xảy ra trước khi phân tích ngữ nghĩa, tức là bộ tiền xử lý không có khái niệm về loại.
vinc17

Phương pháp "Giá trị lớn nhất của bất kỳ loại tích phân có dấu nào" ở đây dựa trên các giả định, mặc dù những giả định rất phổ biến. Lưu ý rằng mặc dù hiếm, xxx_MAX == Uxxx_MAXđược cho phép trong C cũng như xxx_MAX < Uxxx_MAX/2. Điều đặc biệt là đó xxx_MAX <= Uxxx_MAXvà cả hai loại đều có cùng kích thước.
chux - Phục hồi Monica

@chux Đối với những gì tôi đã biết cho đến nay, charlà loại tiêu chuẩn C duy nhất có thể đáp ứng xxx_MAX == Uxxx_MAX, charcó thể có dấu hoặc không dấu tùy thuộc vào việc triển khai. Và đối với xxx_MAX < Uxxx_MAX/2trường hợp này, rất có thể nó được gây ra bởi số học phần bù không phải của 2 (nếu không sẽ không có ý nghĩa đối với việc triển khai).
Explorer

1
~((t) 0)không hoạt động khi (t)0hẹp hơn an int.
chux - Phục hồi Monica

1
@chux Cảm ơn vì gợi ý về ~((t) 0). Đối với các trường hợp xxx_MAX == Uxxx_MAXxxx_MAX < Uxxx_MAX/2trường hợp, từ những gì tôi đã đọc trong tiêu chuẩn C99, vâng chúng được phép.
Explorer09

4

Chúng ta có thể chỉ cần lấy giá trị cao nhất của kiểu dữ liệu không dấu và trừ nó khỏi giá trị lớn nhất để có giá trị nhỏ nhất.
Akansh

1
Đây là một câu trả lời tuyệt vời, không phụ thuộc vào hệ thống, thể hiện sự hiểu biết về các kiểu, bộ nhớ và tất nhiên là các toán tử C bitwise.
Jonathan Komar

@JonathanKomar Tất cả những điều trên tối thiểu ký giả định một kiến trúc 2 của bổ sung, mà thường là - nhưng không phải lúc nào - trường hợp trong C.
jschultz410

Chỉnh sửa: phụ thuộc vào hệ thống (giả sử diễn giải bổ sung của 2 bit) Cảm ơn jschultz410.
Jonathan Komar

3

Hãy xem các trang này trên limit.hfloat.h , được bao gồm như một phần của thư viện c tiêu chuẩn.


3

Tôi đã viết một số macro trả về giá trị tối thiểu và tối đa của bất kỳ loại nào, bất kể độ ký:

Mã ví dụ:


3

Tệp tiêu đề limits.hxác định các macro mở rộng đến các giới hạn và tham số khác nhau của các kiểu số nguyên chuẩn.


giá trị tối thiểu của unsigned char là bao nhiêu?
SuperString

4
@Superstring, giá trị nhỏ nhất của bất kỳ unsigned loại là 0.
Đánh dấu Elliot

4
Tôi muốn các giá trị không dấu âm! :-)
Alok Singhal

2

Để có được giá trị lớn nhất của một kiểu dữ liệu integer unsigned tcó chiều rộng tối thiểu là một trong những unsigned int(nếu không ai được vấn đề với chương trình khuyến mãi số nguyên): ~(t) 0. Nếu ai muốn cũng hỗ trợ các kiểu ngắn hơn, người ta có thể thêm dàn diễn viên khác: (t) ~(t) 0.

Nếu kiểu số nguyên tđược ký, giả sử rằng không có bit đệm, người ta có thể sử dụng:

Ưu điểm của công thức này là nó không dựa trên một số phiên bản không dấu của t(hoặc một loại lớn hơn), có thể không xác định hoặc không có sẵn (thậm chí uintmax_tcó thể không đủ với các phần mở rộng không chuẩn). Ví dụ với 6 bit (không thể thực hiện được trong thực tế, chỉ để dễ đọc):

Trong phần bù của hai, giá trị nhỏ nhất đối lập với giá trị lớn nhất, trừ đi 1 (trong các đại diện số nguyên khác được tiêu chuẩn ISO C cho phép, giá trị này chỉ ngược lại với giá trị lớn nhất).

Lưu ý: Để phát hiện tính có dấu để quyết định sử dụng phiên bản nào: (t) -1 < 0sẽ hoạt động với bất kỳ biểu diễn số nguyên nào, đưa ra 1 (đúng) cho các kiểu số nguyên có dấu và 0 (sai) cho các kiểu số nguyên không dấu. Vì vậy, người ta có thể sử dụng:


Đối với max có dấu, tại sao không đơn giản hơn (~ ((t) 1 << (sizeof (t) * CHAR_BIT - 1)))?
jschultz410

1
@ jschultz410 Vì đây là hành vi không xác định. Giá trị toán học (và dương) 2 đối với sizeof(t) * CHAR_BIT - 1không thể biểu diễn trong kiểu có dấu t. Bạn đang giả định hành vi "bao bọc" của dịch chuyển trái, không phải là tiêu chuẩn (và có thể không thành công với việc tối ưu hóa trình biên dịch) và thậm chí sẽ không có ý nghĩa trong các biểu diễn số nguyên khác với phần bổ sung của hai (như tiêu chuẩn C cho phép).
vinc17

0

Giá trị MIN và MAX của bất kỳ kiểu dữ liệu số nguyên nào có thể được tính toán mà không cần sử dụng bất kỳ hàm thư viện nào như bên dưới và logic tương tự có thể được áp dụng cho các kiểu số nguyên khác là short, int và long.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.