CHAR_BIT là gì?


91

Trích dẫn mã để tính toán giá trị tuyệt đối số nguyên (abs) không phân nhánh từ http://graphics.stanford.edu/~seander/bithacks.html :

int v;           // we want to find the absolute value of v
unsigned int r;  // the result goes here 
int const mask = v >> sizeof(int) * CHAR_BIT - 1;

r = (v + mask) ^ mask;

Biến thể được cấp bằng sáng chế:

r = (v ^ mask) - mask;

Nó là gì CHAR_BITvà sử dụng nó như thế nào?

Câu trả lời:


-1

Bạn nên biết rằng mã này phụ thuộc vào hành vi được xác định bằng cách triển khai của dịch chuyển bit phải trên các loại có dấu. gcc hứa hẹn sẽ luôn cung cấp hành vi lành mạnh (dấu hiệu-bit-mở rộng) nhưng ISO C cho phép việc triển khai không lấp đầy các bit phía trên.

Một cách giải quyết vấn đề này:

#ifdef HAVE_SIGN_EXTENDING_BITSHIFT
int const mask = v >> sizeof(int) * CHAR_BIT - 1;
#else
int const mask = -((unsigned)v >> sizeof(int) * CHAR_BIT - 1);
#endif

Của bạn Makefilehoặc config.hv.v. có thể xác định HAVE_SIGN_EXTENDING_BITSHIFTtại thời điểm xây dựng tùy thuộc vào nền tảng của bạn.


120
Tôi không hiểu làm thế nào đây có thể là một câu trả lời được chấp nhận vì nó không trả lời câu hỏi, mặc dù đó là một nhận xét rất thú vị.
qdii

15
@Mauris: Ai đó đã chỉnh sửa câu hỏi và thăng một câu hỏi phụ vào tiêu đề câu hỏi. Tiêu đề ban đầu được thừa nhận là khủng khiếp, nhưng câu hỏi của OP là về cách thức hoạt động của mã bit hack được trích dẫn và "nó không, ít nhất là không di động, và đây là lý do tại sao" là một câu trả lời hữu ích.
R .. GitHub DỪNG TRỢ GIÚP

12
À, tôi hiểu rồi. Đáng buồn thay, câu hỏi này hiển thị rất cao trong kết quả Tìm kiếm của Google cho "What is CHAR_BIT?" , ngay cả khi đó không phải là câu hỏi ban đầu. :( Với lời giải thích của bạn, tôi hiểu tại sao bạn viết câu trả lời này, nhưng đối với hậu thế, có thể hữu ích hơn nếu (a) xóa câu trả lời của bạn và viết lại nó dưới dạng nhận xét cho câu hỏi, để @ AraK's hiển thị ở trên cùng, hoặc (b) chỉnh sửa câu trả lời của bạn để nó trả lời tiêu đề hiện tại của câu hỏi.
Lynn

1
Do sự khác biệt về (các) ý định giữa câu hỏi ban đầu của OP và cách giải thích của người biên tập về câu hỏi đó, có vẻ như bản chất của yêu cầu ban đầu đã vô tình bị thay đổi. Mặc dù cả hai câu hỏi (nguyên bản và chỉnh sửa) đều có giá trị, nhưng sự khác biệt này cần được giải quyết. Bây giờ tôi hỏi: Câu trả lời này có thể được thêm vào wiki không? Điều này có thể sẽ giúp những người đang tìm kiếm loại thông tin này, mặc dù nó không liên quan đến câu hỏi ban đầu. Sau đó, câu hỏi có thể được chỉnh sửa lại để phù hợp với yêu cầu ban đầu của dato datuashvili. Chỉ cần một người đọc quan tâm ...

2
Tôi chỉ xem lịch sử của câu hỏi này và câu hỏi ban đầu không thực sự hỏi ở đâu cách mã hoạt động. Câu hỏi mà người biên tập thăng chức danh là câu hỏi thực tế duy nhất trong đó.
plugwash

224

CHAR_BITlà số bit trong char. Ngày nay, hầu như tất cả các kiến ​​trúc sử dụng 8 bit mỗi byte nhưng không phải lúc nào cũng vậy. Một số máy cũ thường có byte 7-bit.

Nó có thể được tìm thấy trong <limits.h>.


3
Một số DSP có 10 bit-byte trở lên.
Juri Robl

64
C yêu cầu CHAR_BIT>=8và cho phép các giá trị lớn hơn nhiều đối với các DSP chỉ có một kích thước loại duy nhất, thường là 32bit. POSIX yêu cầu CHAR_BIT==8. Nói chung, bạn có thể giả định bất kỳ kiến ​​trúc hướng đến máy chủ đa nhiệm / đa nhiệm hoặc hướng sử dụng tương tác với bất kỳ cơ hội nào được kết nối với internet hoặc trao đổi dữ liệu dạng văn bản với thế giới bên ngoài CHAR_BIT==8.
R .. GitHub DỪNG GIÚP ICE

6
@caf: Không, đó là C99 yêu cầu các loại int8_tuint8_ttồn tại. Do đó tồn tại một loại chiều rộng 8. Vì sizeofbất kỳ loại nào cũng phải tương thích với sizeof charthực tế sizeof int8_tphải là 1. Vì vậy CHAR_BIT == 8. Tôi đã viết vài điều xung quanh sự bảo tồn đó ở đây: gustedt.wordpress.com/2010/06/01/how-many-bits-has-a-byte
Jens Gustedt

22
@Jens Gustedt: Vui lòng trích dẫn một phần trong thông số kỹ thuật C99. Trong số các loại số nguyên có chiều rộng chính xác, thông số C99 cho biết "Các loại này là tùy chọn." (7.18.1.1/3) Tuy nhiên, loại chiều rộng tối thiểu và chiều rộng nhanh nhất là bắt buộc.
jamesdlin

3
@jamesdlin & caf: xin lỗi tôi đã trộn lẫn mọi thứ. vâng, yêu cầu mà tôi đề cập đến thực sự đến từ POSIX stdint.h. Vì vậy, nó bắt buộc phải có, và nó cũng được đánh dấu là Mở rộng cho tiêu chuẩn ISO C , mà không đề cập đến một phiên bản cụ thể của tiêu chuẩn đó. Lỗi của tôi.
Jens Gustedt

2

Cố gắng trả lời cả câu hỏi rõ ràng (CHAR_BIT là gì) và câu hỏi ngầm (cách này hoạt động như thế nào) trong câu hỏi ban đầu.


Một ký tự trong C và C ++ đại diện cho đơn vị bộ nhớ nhỏ nhất mà chương trình C có thể xử lý *

CHAR_BIT trong C và C ++ đại diện cho số lượng bit trong một ký tự. Nó luôn phải có ít nhất 8 do các yêu cầu khác về loại ký tự. Trên thực tế, trên tất cả các máy tính đa năng hiện đại, nó chính xác là 8 nhưng một số hệ thống lịch sử hoặc chuyên dụng có thể có giá trị cao hơn.

Java không có CHAR_BIT hoặc sizeof tương đương, không cần nó vì tất cả các kiểu nguyên thủy trong Java đều có kích thước cố định và cấu trúc bên trong của các đối tượng là không rõ ràng đối với người lập trình. Nếu dịch mã này sang Java, bạn chỉ cần thay thế "sizeof (int) * CHAR_BIT - 1" bằng giá trị cố định 31.

Trong mã cụ thể này, nó đang được sử dụng để tính số bit trong một int. Lưu ý rằng phép tính này giả định rằng kiểu int không chứa bất kỳ bit đệm nào.

Giả sử rằng trình biên dịch của bạn chọn ký mở rộng trên sự thay đổi bit của các số có dấu và giả sử hệ thống của bạn sử dụng biểu diễn bổ sung 2s cho các số âm, điều này có nghĩa là "MASK" sẽ là 0 cho giá trị dương hoặc 0 và -1 cho giá trị âm.

Để phủ định một số bổ sung hai phần, chúng ta cần thực hiện bitwise not và sau đó thêm một số. Tương tự, chúng ta có thể trừ đi một và sau đó phủ định bitwise.

Một lần nữa, giả sử biểu diễn bổ sung hai phần -1 được biểu diễn bởi tất cả những cái, vì vậy loại trừ hoặc với -1 là tương đương với phủ định bit.

Vì vậy, khi v bằng 0, số đó được để lại một mình, khi v là một thì nó bị phủ định.

Một điều cần lưu ý là tràn đã ký trong C và C ++ là hành vi không xác định. Vì vậy, việc sử dụng triển khai ABS này trên giá trị âm nhất dẫn đến hành vi không xác định. Điều này có thể được khắc phục bằng cách thêm các phôi sao cho dòng cuối cùng của chương trình được đánh giá trong int unsigned.

* Thường nhưng không giống đơn vị bộ nhớ nhỏ nhất mà phần cứng có thể xử lý. Việc triển khai có khả năng kết hợp nhiều đơn vị bộ nhớ địa chỉ phần cứng thành một đơn vị bộ nhớ địa chỉ chương trình hoặc chia một đơn vị bộ nhớ địa chỉ phần cứng thành nhiều đơn vị bộ nhớ có thể bổ sung theo chương trình.

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.