it-swarm-vi.tech

A char không phải là gì?

Trong C/C++, unsigned char được sử dụng để làm gì? Nó khác với char thông thường như thế nào?

433
Landon Kuhn

Trong C++, có ba loại ký tự riêng biệt :

  • charname__
  • _signed char_
  • _unsigned char_

Nếu bạn đang sử dụng các loại ký tự cho văn bản , hãy sử dụng charkhông đủ tiêu chuẩn:

  • nó là loại ký tự chữ như _'a'_ hoặc _'0'_.
  • nó là kiểu tạo nên các chuỗi C như _"abcde"_

Nó cũng hoạt động như một giá trị số, nhưng không xác định được giá trị đó được coi là đã ký hay chưa ký. Coi chừng so sánh nhân vật thông qua sự bất bình đẳng - mặc dù nếu bạn giới hạn bản thân ở ASCII (0-127) thì bạn chỉ an toàn.

Nếu bạn đang sử dụng các loại ký tự dưới dạng số , hãy sử dụng:

  • _signed char_, cung cấp cho bạn ít nhất phạm vi -127 đến 127. (-128 đến 127 là phổ biến)
  • _unsigned char_, cung cấp cho bạn ít nhất phạm vi từ 0 đến 255.

"Ít nhất", bởi vì tiêu chuẩn C++ chỉ đưa ra phạm vi giá trị tối thiểu mà mỗi loại số được yêu cầu để che. sizeof (char) được yêu cầu là 1 (tức là một byte), nhưng về mặt lý thuyết, một byte có thể là 32 bit. sizeofNAME__ VẪN SẼ ĐƯỢC BÁO CÁO KÍCH THƯỚC CỦA NÓ LÀ _1 - có nghĩa là bạn có thể sizeof (char) == sizeof (long) == 1.

520
Fruny

Điều này phụ thuộc vào việc triển khai, vì tiêu chuẩn C KHÔNG xác định mức độ đã ký của char. Tùy thuộc vào nền tảng, char có thể là signed hoặc unsigned, vì vậy bạn cần yêu cầu rõ ràng về signed char hoặc unsigned char nếu việc triển khai của bạn phụ thuộc vào nó. Chỉ cần sử dụng char nếu bạn có ý định đại diện cho các ký tự từ các chuỗi, vì điều này sẽ khớp với những gì nền tảng của bạn đặt trong chuỗi.

Sự khác biệt giữa signed charunsigned char là như bạn mong đợi. Trên hầu hết các nền tảng, signed char sẽ là số bổ sung 8 bit hai, từ -128 đến 127unsigned char sẽ là số nguyên không dấu 8 bit (0 đến 255). Lưu ý rằng tiêu chuẩn KHÔNG yêu cầu các loại char có 8 bit, chỉ có điều đó sizeof(char) trả về 1. Bạn có thể nhận được số bit trong một char với CHAR_BIT trong limits.h. Mặc dù vậy, có rất ít nếu có bất kỳ nền tảng nào hiện nay, nơi đây sẽ là một cái gì đó không phải là 8.

Có một bản tóm tắt hay về vấn đề này tại đây .

Như những người khác đã đề cập kể từ khi tôi đăng bài này, tốt hơn hết bạn nên sử dụng int8_tuint8_t nếu bạn thực sự muốn đại diện cho các số nguyên nhỏ.

81
Todd Gamblin

Bởi vì tôi cảm thấy nó thực sự được yêu cầu, tôi chỉ muốn nêu ra một số quy tắc của C và C++ (chúng giống nhau về vấn đề này). Đầu tiên, tất cả các bit of unsigned char tham gia xác định giá trị nếu có bất kỳ đối tượng char không dấu nào. Thứ hai, unsigned char được ghi rõ ràng không dấu.

Bây giờ, tôi đã thảo luận với ai đó về những gì xảy ra khi bạn chuyển đổi giá trị -1 của kiểu int thành unsigned char. Anh ta từ chối ý tưởng rằng unsigned char có tất cả các bit của nó được đặt thành 1, vì anh ta lo lắng về biểu diễn dấu hiệu. Nhưng anh không phải làm thế. Ngay lập tức tuân theo quy tắc này là việc chuyển đổi thực hiện những gì được dự định:

Nếu loại mới không được ký, giá trị được chuyển đổi bằng cách lặp lại hoặc trừ đi nhiều hơn một giá trị tối đa có thể được biểu thị trong loại mới cho đến khi giá trị nằm trong phạm vi của loại mới. (6.3.1.3p2 trong bản nháp C99)

Đó là một mô tả toán học. C++ mô tả nó theo tính toán modulo, điều này dẫn đến cùng một quy tắc. Dù sao, điều không được đảm bảo là tất cả các bit trong số nguyên -1 là một trước khi chuyển đổi. Vì vậy, chúng ta có gì để chúng ta có thể tuyên bố rằng kết quả unsigned char có tất cả các bit CHAR_BIT của nó được chuyển thành 1?

  1. Tất cả các bit tham gia vào việc xác định giá trị của nó - nghĩa là, không có bit đệm nào xảy ra trong đối tượng.
  2. Chỉ thêm một lần UCHAR_MAX+1 vào -1 sẽ mang lại một giá trị trong phạm vi, cụ thể là UCHAR_MAX

Thế là đủ rồi! Vì vậy, bất cứ khi nào bạn muốn có một unsigned char có tất cả các bit của nó, bạn sẽ làm

unsigned char c = (unsigned char)-1;

Nó cũng theo sau rằng một chuyển đổi là không chỉ cắt các bit thứ tự cao hơn. Sự kiện may mắn cho hai phần bổ sung là nó chỉ là một phần cắt ở đó, nhưng điều tương tự không nhất thiết đúng với các biểu diễn dấu hiệu khác.

35

Ví dụ: tập quán của unsign char :

char unsign thường được sử dụng trong đồ họa máy tính, điều này rất thường xuyên (mặc dù không phải lúc nào) chỉ định một byte cho mỗi thành phần màu. Người ta thường thấy màu RGB (hoặc RGBA) được biểu thị bằng 24 bit (hoặc 32), mỗi bit char không dấu . Vì giá trị char không dấu nằm trong phạm vi [0,255], nên các giá trị thường được hiểu là:

  • 0 có nghĩa là thiếu hoàn toàn một thành phần màu nhất định.
  • 255 có nghĩa là 100% của một sắc tố màu nhất định.

Vì vậy, bạn sẽ kết thúc với màu đỏ RGB là (255,0,0) -> (đỏ 100%, xanh 0%, xanh 0%).

Tại sao không sử dụng ký tự char ? Số học và bit dịch chuyển trở thành vấn đề. Như đã giải thích, phạm vi của đã ký char về cơ bản được thay đổi bởi -128. Một phương pháp rất đơn giản và ngây thơ (hầu hết không được sử dụng) để chuyển đổi RGB sang thang độ xám là trung bình cả ba thành phần màu, nhưng điều này gặp vấn đề khi các giá trị của các thành phần màu là âm. Màu đỏ (255, 0, 0) trung bình đến (85, 85, 85) khi sử dụng số học char không dấu. Tuy nhiên, nếu các giá trị là đã ký char s (127, -128, -128), chúng tôi sẽ kết thúc bằng (-99, -99, -99), sẽ là (29, 29, 29) trong không gian không dấu char của chúng tôi, không chính xác.

24
Zachary Garrett

Nếu bạn muốn sử dụng một ký tự như một số nguyên nhỏ, cách an toàn nhất là sử dụng các loại int8_tuint8_t.

12
jbleners

signed char có phạm vi -128 đến 127; unsigned char có phạm vi từ 0 đến 255.

char sẽ tương đương với char đã ký hoặc char không dấu, tùy thuộc vào trình biên dịch, nhưng là một loại khác biệt.

Nếu bạn đang sử dụng chuỗi kiểu C, chỉ cần sử dụng char. Nếu bạn cần sử dụng ký tự cho số học (khá hiếm), chỉ định rõ ràng đã ký hoặc không dấu cho tính di động.

5
James Hopkin

charunsigned char không được đảm bảo là loại 8 bit trên tất cả các nền tảng, chúng được đảm bảo là 8 bit hoặc lớn hơn. Một số nền tảng có byte 9 bit, 32 bit hoặc 64 bit . Tuy nhiên, các nền tảng phổ biến nhất hiện nay (Windows, Mac, Linux x86, v.v.) có byte 8 bit.

5
bk1e

Về mặt giá trị trực tiếp, một char thông thường được sử dụng khi các giá trị được biết là nằm giữa CHAR_MINCHAR_MAX trong khi một char không dấu cung cấp gấp đôi phạm vi ở đầu dương. Ví dụ: nếu CHAR_BIT là 8, thì phạm vi charthông thường chỉ được đảm bảo là [0, 127] (vì có thể được ký hoặc không dấu) trong khi unsigned char sẽ là [0, 255] và signed char sẽ là [0, 255] ].

Về mặt sử dụng, các tiêu chuẩn cho phép các đối tượng của POD (dữ liệu cũ đơn giản) được chuyển đổi trực tiếp thành một mảng char không dấu. Điều này cho phép bạn kiểm tra biểu diễn và các mẫu bit của đối tượng. Sự bảo đảm tương tự của loại picky an toàn không tồn tại đối với char hoặc char đã ký.

4
Julienne Walker

unsigned char chỉ lấy các giá trị dương .... như đến 255

trong khi

signed char lấy cả giá trị dương và âm .... như - 128 thành + 127

4
munna

Một char không dấu là một giá trị byte (không dấu) (0 đến 255). Bạn có thể nghĩ về "char" trong việc trở thành một "nhân vật" nhưng nó thực sự là một giá trị số. "Char" thông thường được ký, do đó bạn có 128 giá trị và các giá trị này ánh xạ tới các ký tự bằng cách sử dụng mã hóa ASCII. Nhưng trong cả hai trường hợp, những gì bạn đang lưu trữ trong bộ nhớ là một giá trị byte.

3
Zac Gochenour

Nếu bạn thích sử dụng nhiều loại độ dài và độ ký cụ thể khác nhau, có lẽ bạn nên sử dụng uint8_t, int8_t, uint16_t, v.v.

2
Dark Shikari

Một char không dấu sử dụng bit được dành riêng cho dấu của một char thông thường như một số khác. Điều này thay đổi phạm vi thành [0 - 255] trái ngược với [-128 - 127].

Các ký tự không dấu thường được sử dụng khi bạn không muốn có một dấu hiệu. Điều này sẽ tạo ra sự khác biệt khi thực hiện những việc như dịch chuyển bit (shift mở rộng dấu) và những thứ khác khi xử lý char dưới dạng byte thay vì sử dụng nó làm số.

2
JasonOfEarth

unsign char là trái tim của tất cả các mánh khóe bit. Trong hầu hết TẤT CẢ trình biên dịch cho TẤT CẢ nền tảng, char không dấu chỉ đơn giản là BYTE. Một số nguyên không dấu của (thường) 8 bit. có thể được coi là một số nguyên nhỏ hoặc một gói bit.

Trong nghiện, như người khác đã nói, tiêu chuẩn không xác định dấu hiệu của một char. vì vậy bạn có 3 loại "char" riêng biệt: char, char đã ký, char không dấu.

2
ugasoft

Một số googling được tìm thấy này , nơi mọi người đã thảo luận về điều này.

Một char không dấu về cơ bản là một byte đơn. Vì vậy, bạn sẽ sử dụng điều này nếu bạn cần một byte dữ liệu (ví dụ: có thể bạn muốn sử dụng nó để đặt và tắt cờ được chuyển đến một chức năng, như thường được thực hiện trong API Windows).

1
dbrien

char không dấu chỉ nhận các giá trị dương: 0 đến 255 char đã ký có các giá trị dương và âm: -128 đến +127

0
NL628

trích dẫn từ cuốn sách "hành vi lập trình c":

Vòng loại signed hoặc unsigned có thể được áp dụng cho char hoặc bất kỳ số nguyên nào. số không dấu luôn luôn dương hoặc bằng 0 và tuân theo định luật modulo số học 2 ^ n, trong đó n là số bit trong loại. Vì vậy, ví dụ, nếu các ký tự là 8 bit, các biến char không dấu có các giá trị trong khoảng từ 0 đến 255, trong khi các ký tự được ký có các giá trị trong khoảng từ -128 đến 127 (trong máy bù hai.) Cho dù các ký tự đơn giản được ký hoặc không dấu là máy phụ thuộc, nhưng các ký tự có thể in luôn luôn tích cực.

0
ZhaoGang