2016-11-26 11 views
15

Tôi đã chuyển sang các loại số nguyên có độ dài cố định trong các dự án của mình chủ yếu là vì chúng giúp tôi suy nghĩ về kích thước số nguyên rõ ràng hơn khi sử dụng chúng. Bao gồm họ qua #include <inttypes.h> cũng bao gồm một loạt các macro khác như các macro in PRIu32, PRIu64 ...Khi nào tôi nên sử dụng các macro UINT32_C(), INT32_C(), ... trong C?

Để gán một giá trị không đổi cho một biến chiều dài cố định tôi có thể sử dụng các macro như UINT32_C()INT32_C(). Tôi bắt đầu sử dụng chúng bất cứ khi nào tôi gán một giá trị không đổi.

Điều này dẫn đến mã tương tự như sau:

uint64_t i; 
for (i = UINT64_C(0); i < UINT64_C(10); i++) { ... } 

Bây giờ tôi thấy một số ví dụ mà không quan tâm về điều đó. Một là stdbool.h bao gồm file:

#define bool _Bool 
#define false 0 
#define true 1 

bool có kích thước 1 byte trên máy tính của tôi, vì vậy nó không giống như một int. Nhưng 01 phải là số nguyên nên được trình biên dịch tự động chuyển thành đúng loại. Nếu tôi sẽ sử dụng trong ví dụ của tôi mã sẽ dễ dàng hơn nhiều để đọc:

uint64_t i; 
for (i = 0; i < 10; i++) { ... } 

Vì vậy, khi tôi nên sử dụng độ dài cố định liên tục macro như UINT32_C() và khi nào tôi nên rời bỏ công việc đó để trình biên dịch (tôi sử dụng GCC)? Nếu tôi viết mã trong MISRA C thì sao?

+3

Cá nhân tôi tránh xa việc sử dụng các loại chiều rộng cố định: không phải tất cả trình biên dịch đều hỗ trợ chúng và quy tắc quảng cáo với các loại này thực tế không tồn tại - theo ý kiến ​​khiêm tốn của tôi về sự giám sát lớn trong tiêu chuẩn C. Upvote cho câu hỏi mặc dù. – Bathsheba

+1

Câu hỏi thú vị, không thể chờ đợi để xem câu trả lời – cat

+1

Bạn có thể cần chúng nếu 'int' hẹp ​​hơn 32 bit. – nwellnhof

Trả lời

4

Theo quy tắc chung, bạn nên sử dụng chúng khi loại vấn đề theo nghĩa đen. Có hai điều cần xem xét: kích thước và sự ký kết.

Về kích thước:

Một loại int được đảm bảo bởi các giá trị tiêu chuẩn C lên đến 32767. Vì bạn không thể nhận được một số nguyên bằng một loại nhỏ hơn int, tất cả các giá trị nhỏ hơn 32767 không cần phải sử dụng các macro. Nếu bạn cần các giá trị lớn hơn, thì loại chữ bắt đầu thành vấn đề và bạn nên sử dụng các macro đó.

Về ký kết:

Chữ số nguyên không có hậu tố thường là loại đã ký. Điều này có khả năng nguy hiểm, vì nó có thể gây ra tất cả các cách lỗi tinh vi trong khi quảng bá loại ngầm. Ví dụ: (my_uint8_t + 1) << 31 sẽ gây ra lỗi hành vi không xác định trên hệ thống 32 bit, trong khi (my_uint8_t + 1u) << 31 thì không.

Đây là lý do tại sao MISRA có quy tắc cho biết tất cả các số nguyên nguyên phải có hậu tố u/U nếu ý định là sử dụng các loại chưa ký. Vì vậy, trong ví dụ trên, bạn có thể sử dụng my_uint8_t + UINT32_C(1) nhưng bạn cũng có thể sử dụng 1u, có lẽ là dễ đọc nhất. Hoặc là tốt cho MISRA.


Vì lý do tại sao stdbool.h định nghĩa đúng/sai thành 1/0, đó là do tiêu chuẩn nói rõ như vậy. Các điều kiện Boolean trong C vẫn sử dụng loại int và không loại bool loại như trong C++, vì các lý do tương thích ngược.

Tuy nhiên, đây được coi là kiểu tốt để xử lý các điều kiện boolean như thể C có kiểu boolean thực. MISRA-C: 2012 có toàn bộ các quy tắc liên quan đến khái niệm này, được gọi là về cơ bản là loại boolean. Điều này có thể cung cấp cho loại an toàn hơn trong quá trình phân tích tĩnh và cũng có thể ngăn chặn các lỗi khác nhau.

+0

Kích thước số nguyên không quan trọng. Các chữ số nguyên sẽ là loại nhỏ nhất có thể chứa giá trị của chữ, hoặc ('unsigned')' int', tùy theo giá trị nào lớn hơn. – alecov

2

Đó là để sử dụng các chữ số nguyên nhỏ, trong đó ngữ cảnh sẽ không dẫn đến trình biên dịch truyền nó đến đúng kích cỡ.

Tôi đã làm việc trên nền tảng được nhúng trong đó int là 16 bit và long là 32 bit. Nếu bạn đang cố gắng viết mã di động để làm việc trên nền tảng với loại 162 bit hoặc 32-bit int và muốn chuyển 32 bit "chữ số nguyên không dấu" sang hàm variadic, bạn cần có dàn diễn viên:

#define BAUDRATE UINT32_C(38400) 
printf("Set baudrate to %" PRIu32 "\n", BAUDRATE); 

Trên nền tảng 16 bit, dàn diễn viên tạo 38400UL và trên nền tảng 32 bit chỉ 38400U. Những quảng cáo đó sẽ khớp với macro PRIu32 của "lu" hoặc "u".

Tôi nghĩ rằng hầu hết các trình biên dịch sẽ tạo mã giống nhau cho (uint32_t) X như đối với UINT32_C(X) khi X là một số nguyên, nhưng có thể không phải là trường hợp với trình biên dịch đầu.

+0

Tôi chấp nhận câu trả lời của Lundins, nhưng 1 để đề cập đến các hàm variadic. – TimFinnegan

Các vấn đề liên quan