Tôi sử dụng ints không dấu để làm cho mã của tôi và ý định của nó rõ ràng hơn. Một điều tôi làm để bảo vệ chống lại các chuyển đổi ngầm bất ngờ khi thực hiện số học với cả hai loại đã ký và không dấu là sử dụng một ký hiệu ngắn không dấu (thường là 2 byte) cho các biến không dấu của tôi. Điều này có hiệu quả vì một vài lý do:
- Khi bạn thực hiện số học với các biến và ký tự ngắn không dấu (thuộc kiểu int) hoặc biến kiểu int, điều này đảm bảo biến không dấu sẽ luôn được thăng cấp thành int trước khi đánh giá biểu thức, vì int luôn có thứ hạng cao hơn ngắn . Điều này tránh mọi hành vi không mong muốn thực hiện số học với các loại đã ký và không dấu, giả sử kết quả của biểu thức phù hợp với một int đã ký tất nhiên.
- Hầu hết thời gian, các biến không dấu mà bạn đang sử dụng sẽ không vượt quá giá trị tối đa của một byte ngắn 2 byte không dấu (65,535)
Nguyên tắc chung là loại biến không dấu của bạn phải có thứ hạng thấp hơn loại biến được ký để đảm bảo thăng hạng cho loại đã ký. Sau đó, bạn sẽ không có bất kỳ hành vi tràn bất ngờ. Rõ ràng là bạn không thể đảm bảo điều này mọi lúc, nhưng (hầu hết) thường là khả thi để đảm bảo điều này.
Ví dụ, gần đây tôi có một số vòng lặp như thế này:
const unsigned short cuint = 5;
for(unsigned short i=0; i<10; ++i)
{
if((i-2)%cuint == 0)
{
//Do something
}
}
Chữ "2" theo kiểu int. Nếu tôi là một số nguyên không dấu thay vì một ký hiệu không dấu, thì trong biểu thức con (i-2), 2 sẽ được thăng cấp thành một số không dấu (vì số nguyên không dấu có mức độ ưu tiên cao hơn số nguyên được ký). Nếu i = 0, thì biểu thức con bằng (0u-2u) = một số giá trị lớn do tràn. Cùng một ý tưởng với i = 1. Tuy nhiên, vì tôi là một dấu ngắn không dấu, nên nó được quảng cáo cùng loại với nghĩa đen là '2', được ký tên int và mọi thứ đều hoạt động tốt.
Để an toàn hơn: trong trường hợp hiếm khi kiến trúc bạn triển khai với nguyên nhân int là 2 byte, điều này có thể khiến cả hai toán hạng trong biểu thức số học được thăng cấp thành int unsign trong trường hợp biến ngắn không dấu không khớp vào int 2 byte đã ký, cái sau có giá trị tối đa là 32.767 <65.535. (Xem https://stackoverflow.com/questions/17832815/c-implicit-conversion-sign-unign để biết thêm chi tiết). Để chống lại điều này, bạn chỉ cần thêm static_assert vào chương trình của mình như sau:
static_assert(sizeof(int) == 4, "int must be 4 bytes");
và nó sẽ không biên dịch trên các kiến trúc trong đó int là 2 byte.
for(unsigned int n = 10; n >= 0; n --)
(vòng lặp vô hạn)