Lợi thế của việc sử dụng là gì uint8_t
so với unsigned char
trong C?
Tôi biết rằng trên hầu hết mọi hệ thống uint8_t
chỉ là một typedef unsigned char
, vậy tại sao lại sử dụng nó?
Lợi thế của việc sử dụng là gì uint8_t
so với unsigned char
trong C?
Tôi biết rằng trên hầu hết mọi hệ thống uint8_t
chỉ là một typedef unsigned char
, vậy tại sao lại sử dụng nó?
Câu trả lời:
Nó ghi lại ý định của bạn - bạn sẽ lưu trữ những con số nhỏ, thay vì một ký tự.
Ngoài ra, nó trông đẹp hơn nếu bạn đang sử dụng các typedefs khác như uint16_t
hoặc int32_t
.
unsigned char
hoặc signed char
ghi lại ý định, vì không char
được cung cấp là những gì cho thấy bạn đang làm việc với các nhân vật.
unsigned
được trang bị là unsigned int
theo định nghĩa?
char
dường như ngụ ý một ký tự, trong khi trong ngữ cảnh của chuỗi UTF8, nó có thể chỉ là một byte của một ký tự đa dòng. Sử dụng uint8_t có thể làm rõ rằng người ta không nên mong đợi một ký tự ở mọi vị trí - nói cách khác, mỗi phần tử của chuỗi / mảng là một số nguyên tùy ý mà người ta không nên đưa ra bất kỳ giả định ngữ nghĩa nào. Tất nhiên tất cả các lập trình viên C đều biết điều này, nhưng nó có thể thúc đẩy những người mới bắt đầu hỏi đúng câu hỏi.
Chỉ là phạm vi, một số hệ thống có thể không có loại 8 bit. Theo Wikipedia :
Việc triển khai là bắt buộc để xác định các loại số nguyên có chiều rộng chính xác cho N = 8, 16, 32 hoặc 64 khi và chỉ khi nó có bất kỳ loại nào đáp ứng yêu cầu. Không bắt buộc phải định nghĩa chúng cho bất kỳ N nào khác, ngay cả khi nó hỗ trợ các loại thích hợp.
Vì vậy, uint8_t
không được đảm bảo tồn tại, mặc dù nó sẽ dành cho tất cả các nền tảng có 8 bit = 1 byte. Một số nền tảng nhúng có thể khác nhau, nhưng điều đó rất hiếm. Một số hệ thống có thể định nghĩa char
các loại là 16 bit, trong trường hợp đó có thể sẽ không có loại 8 bit nào.
Ngoài vấn đề (nhỏ) đó, câu trả lời của @Mark Ransom là tốt nhất theo quan điểm của tôi. Sử dụng dữ liệu thể hiện rõ nhất những gì bạn đang sử dụng dữ liệu.
Ngoài ra, tôi giả sử bạn có nghĩa là uint8_t
(typedef tiêu chuẩn từ C99 được cung cấp trong stdint.h
tiêu đề) chứ không phải uint_8
(không phải là một phần của bất kỳ tiêu chuẩn nào).
uint8_t
(hoặc gõ nó theo cách đó). Điều này là do loại 8 bit sẽ có các bit không được sử dụng trong biểu diễn lưu trữ, mà uint8_t
không phải có.
typedef unsigned integer type uint8_t; // optional
Vì vậy, về bản chất, không cần một thư viện tuân thủ tiêu chuẩn C ++ để xác định uint8_t (xem bình luận // tùy chọn // )
Toàn bộ vấn đề là viết mã độc lập thực hiện. unsigned char
không được đảm bảo là loại 8 bit. uint8_t
là (nếu có).
sizeof(unsigned char)
sẽ trả về 1
1 byte. nhưng nếu một char hệ thống và int có cùng kích thước, ví dụ 16 bit thì sizeof(int)
cũng sẽ quay trở lại1
Như bạn đã nói, " hầu hết mọi hệ thống".
char
có lẽ là một trong những ít có khả năng thay đổi, nhưng một khi bạn bắt đầu sử dụng uint16_t
và bạn bè, sử dụng uint8_t
hỗn hợp tốt hơn, và thậm chí có thể là một phần của tiêu chuẩn mã hóa.
Theo kinh nghiệm của tôi, có hai nơi chúng tôi muốn sử dụng uint8_t có nghĩa là 8 bit (và uint16_t, v.v.) và nơi chúng tôi có thể có các trường nhỏ hơn 8 bit. Cả hai vị trí là nơi không gian quan trọng và chúng ta thường cần xem xét một bãi dữ liệu thô khi gỡ lỗi và cần có thể nhanh chóng xác định những gì nó đại diện.
Đầu tiên là trong các giao thức RF, đặc biệt là trong các hệ thống băng tần hẹp. Trong môi trường này, chúng ta có thể cần phải đóng gói càng nhiều thông tin càng tốt vào một tin nhắn. Thứ hai là trong bộ lưu trữ flash, nơi chúng ta có thể có không gian rất hạn chế (chẳng hạn như trong các hệ thống nhúng). Trong cả hai trường hợp, chúng tôi có thể sử dụng cấu trúc dữ liệu được đóng gói trong đó trình biên dịch sẽ đảm nhiệm việc đóng gói và giải nén cho chúng tôi:
#pragma pack(1)
typedef struct {
uint8_t flag1:1;
uint8_t flag2:1;
padding1 reserved:6; /* not necessary but makes this struct more readable */
uint32_t sequence_no;
uint8_t data[8];
uint32_t crc32;
} s_mypacket __attribute__((packed));
#pragma pack()
Phương pháp bạn sử dụng phụ thuộc vào trình biên dịch của bạn. Bạn cũng có thể cần hỗ trợ một số trình biên dịch khác nhau với cùng một tệp tiêu đề. Điều này xảy ra trong các hệ thống nhúng, nơi các thiết bị và máy chủ có thể hoàn toàn khác nhau - ví dụ: bạn có thể có một thiết bị ARM giao tiếp với máy chủ Linux x86.
Có một vài cảnh báo với việc sử dụng các cấu trúc đóng gói. Gotcha lớn nhất là bạn phải tránh hội thảo địa chỉ của một thành viên. Trên các hệ thống có các từ được sắp xếp bằng mutibyte, điều này có thể dẫn đến một ngoại lệ bị sai lệch - và bị loại bỏ.
Một số người cũng sẽ lo lắng về hiệu suất và lập luận rằng việc sử dụng các cấu trúc đóng gói này sẽ làm chậm hệ thống của bạn. Đúng là, đằng sau hậu trường, trình biên dịch thêm mã để truy cập các thành viên dữ liệu chưa được phân bổ. Bạn có thể thấy điều đó bằng cách nhìn vào mã lắp ráp trong IDE của bạn.
Nhưng vì các cấu trúc đóng gói là hữu ích nhất cho việc lưu trữ và lưu trữ dữ liệu, sau đó dữ liệu có thể được trích xuất thành một biểu diễn không được đóng gói khi làm việc với nó trong bộ nhớ. Thông thường chúng ta không cần phải làm việc với toàn bộ gói dữ liệu trong bộ nhớ.
Đây là một số thảo luận có liên quan:
gói pragma (1) cũng không __attribution__ ((căn chỉnh (1))) hoạt động
Là __attribution __ ((đóng gói)) / #pragma của gcc có an toàn không?
http://solidsmoke.blogspot.ca/2010/07/woes-of-structure-packing-pragma-pack.html
Có rất ít. Từ quan điểm tính di động, char
không thể nhỏ hơn 8 bit và không có gì có thể nhỏ hơn char
, vì vậy nếu một triển khai C đã cho có loại số nguyên 8 bit không dấu, thì nó sẽ như vậy char
. Ngoài ra, nó có thể không có một chút nào, tại thời điểm đó, bất kỳ typedef
thủ thuật nào cũng được đưa ra.
Nó có thể được sử dụng để ghi lại mã của bạn tốt hơn theo nghĩa rõ ràng rằng bạn yêu cầu byte 8 bit ở đó và không có gì khác. Nhưng trong thực tế, đó là một kỳ vọng hợp lý hầu như ở bất cứ đâu đã có (có các nền tảng DSP không đúng sự thật, nhưng khả năng mã của bạn chạy ở đó rất mong manh và bạn cũng có thể gặp lỗi khi sử dụng một xác nhận tĩnh ở đầu chương trình của bạn trên một nền tảng như vậy).
unsigned char
có thể giữ các giá trị trong khoảng từ 0 đến 255. Nếu bạn có thể làm điều đó trong 4 bit, mũ của tôi sẽ tắt cho bạn.
uint8_t
vào để thực hiện. Tôi tự hỏi, các trình biên dịch cho DSP có ký tự 16 bit thường thực hiện uint8_t
hay không?
#include <stdint.h>
và sử dụng uint8_t
. Nếu nền tảng có nó, nó sẽ cung cấp cho bạn. Nếu nền tảng không có nó, chương trình của bạn sẽ không biên dịch và lý do sẽ rõ ràng và đơn giản.
Điều đó thực sự quan trọng, ví dụ khi bạn đang viết một bộ phân tích mạng. tiêu đề gói được xác định bởi đặc tả giao thức, không phải bằng cách trình biên dịch C của một nền tảng cụ thể hoạt động.
Trên hầu hết mọi hệ thống tôi đã gặp uint8_t == char không dấu, nhưng điều này không được đảm bảo bởi tiêu chuẩn C. Nếu bạn đang cố gắng viết mã di động và vấn đề chính xác là kích thước bộ nhớ, hãy sử dụng uint8_t. Nếu không sử dụng char không dấu.
uint8_t
luôn khớp với phạm vi và kích thước unsigned char
và phần đệm (không có) khi unsigned char
là 8 bit. Khi unsigned char
không phải là 8 bit, uint8_t
không tồn tại.
unsigned char
là 8 bit, được uint8_t
đảm bảo là một số typedef
chứ không phải là typedef
một kiểu số nguyên không dấu mở rộng ?
unsigned char/signed char/char
loại nhỏ nhất - không nhỏ hơn 8 bit. unsigned char
không có đệm. Để uint8_t
được, nó phải là 8 bit, không có phần đệm, tồn tại do một kiểu số nguyên được cung cấp: phù hợp với các yêu cầu tối thiểu của unsigned char
. Đối với "... đảm bảo là một typedef ..." có vẻ như là một câu hỏi hay để đăng.