Що таке CHAR_BIT?


91

Цитування коду для обчислення цілочисельного абсолютного значення (абс) без розгалуження з 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;

Запатентована варіація:

r = (v ^ mask) - mask;

Що таке CHAR_BITі як ним користуватися?

Відповіді:


-1

Вам слід пам’ятати, що цей код залежить від поведінки, визначеної реалізацією, правильного бітового зсуву на підписаних типах. gcc обіцяє завжди надавати розумну поведінку (розширення знакових бітів), але ISO C дозволяє реалізації нульового заповнення верхніх бітів.

Один із способів обійти цю проблему:

#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

Ваш Makefileабо config.hінше можна визначити HAVE_SIGN_EXTENDING_BITSHIFTпід час збирання залежно від вашої платформи.


120
Я не розумію, як це може бути прийнятою відповіддю, оскільки вона не відповідає на питання, хоча це дуже цікавий коментар.
qdii

15
@Mauris: Хтось відредагував питання та просунув підзапитання до назви запитання. Оригінальний заголовок, правда, був жахливим, але питання OP стосувалося того, як працює цитований код розлому, і "це не так, принаймні не портативно, і ось чому" є корисною відповіддю.
R .. GitHub СТОП ДОПОМОГАЙ ЛЕД

12
Ах, я розумію. На жаль, це питання відображається дуже високо в результатах пошуку Google щодо "Що таке CHAR_BIT?" , навіть якщо це не було спочатку питання. :) (b) відредагуйте свою відповідь так, щоб вона відповідала поточній назві питання.
Лінн,

1
Через різницю в намірах між оригінальним запитанням ОР та його інтерпретацією редактором, здається, що природа оригінального запиту мимоволі змінена. Хоча обидва питання (оригінальне та відредаговане) заслуговують на увагу, цю невідповідність потрібно усунути. Зараз я запитую: чи можна цю відповідь додати до вікі? Це могло б допомогти людям, які шукають інформацію такого типу, хоча це не стосується вихідного питання. Після цього питання можна було відредагувати ще раз, щоб відповідати початковому запиту дато Датуашвілі. Просто стурбований читач ...

2
Я просто подивився історію цього питання, і оригінальне питання насправді ніде не задає питання про те, як працює код. Питання, яке редактор підвищив до заголовка, є єдиним актуальним питанням там.
plugwash

224

CHAR_BIT- кількість бітів в char. У наші дні майже всі архітектури використовують 8 біт на байт, але це не завжди так. Деякі старі машини раніше мали 7-бітний байт.

Його можна знайти в <limits.h>.


3
Деякі DSP мають 10 і більше біт-байт.
Юрі Робл

64
C вимагає CHAR_BIT>=8і допускає набагато більші значення для ЦСП, які мають лише один розмір типу, часто 32 біт. POSIX вимагає CHAR_BIT==8. Загалом, ви можете припустити будь-яку багатокористувацьку / багатозадачну орієнтовану на сервер чи інтерактивну архітектуру архітектуру з будь-яким шансом на підключення до Інтернету або обмін текстовими даними із зовнішнім світом CHAR_BIT==8.
R .. GitHub СТОП ДОПОМОГАЙ ЛЕДІ

6
@caf: Ні, це те, що C99 вимагає типи int8_tі uint8_tіснувати. Таким чином існує тип ширини 8. Оскільки sizeofбудь-який тип повинен бути сумісним, sizeof charнасправді sizeof int8_tмає бути 1. Отже CHAR_BIT == 8. Я щось написав навколо цього спостереження тут: gustedt.wordpress.com/2010/06/01/how-many-bits-has-a-byte
Jens Gustedt

22
@ Jens Gustedt: Будь ласка, процитуйте розділ у специфікації C99. З цілочисельних типів точної ширини специфікація C99 говорить "Ці типи не є обов'язковими". (7.18.1.1/3) Однак потрібні типи мінімальної та найшвидшої ширини.
jamesdlin

3
@jamesdlin & caf: вибачте, я все змішав. Так, вимога, на яку я посилався, насправді походить від POSIX stdint.h. Отже, це потрібно, і це також позначено як Розширення стандарту ISO C , не посилаючись на конкретну версію цього стандарту. Моє ліжко.
Jens Gustedt

2

Спроба відповісти як на явне запитання (що таке CHAR_BIT), так і на неявне запитання (як це працює) у вихідному питанні.


Символ на мовах C та C ++ являє собою найменшу одиницю пам'яті, на яку може звернутися програма C *

CHAR_BIT в C і C ++ представляє кількість бітів у символі. Завжди має бути принаймні 8 через інші вимоги до типу char. На практиці на всіх сучасних комп'ютерах загального призначення це рівно 8, але деякі історичні або спеціалізовані системи можуть мати вищі значення.

Java не має еквівалента CHAR_BIT або sizeof, у цьому немає необхідності, оскільки всі примітивні типи в Java мають фіксований розмір, а внутрішня структура об'єктів є непрозорою для програміста. При перекладі цього коду на Java ви можете просто замінити "sizeof (int) * CHAR_BIT - 1" на фіксоване значення 31.

У цьому конкретному коді він використовується для обчислення кількості бітів в int. Майте на увазі, що в цьому обчисленні передбачається, що тип int не містить бітів заповнення.

Якщо припустити, що ваш компілятор вирішив підписати розширення на бітові зсуви підписаних чисел і припустивши, що ваша система використовує представлення доповнення 2s для від'ємних чисел, це означає, що "MASK" буде 0 для позитивного або нульового значення і -1 для негативного значення.

Щоб заперечити число доповнення двох, нам потрібно виконати побітове значення, а не додати одне. Еквівалентно ми можемо відняти один, а потім побітово заперечити його.

Знову ж таки, якщо припустити, що представлення доповнення двійки -1 представлене всіма, тому ексклюзив або з -1 еквівалентний розрядному запереченню.

Отже, коли v дорівнює нулю, число залишається одне, коли v дорівнює одиниці, воно заперечується.

Потрібно пам’ятати, що переповнене знаком у C та C ++ є невизначеною поведінкою. Отже, використання цієї реалізації ABS на найбільш негативному значенні призводить до невизначеної поведінки. Це можна виправити, додавши закиди таким чином, що кінцевий рядок програми обчислюється в unsigned int.

* Що, як правило, але не нецерально те саме, що найменша одиниця пам'яті, до якої може звернутися апаратне забезпечення. Реалізація може потенційно об'єднати кілька одиниць апаратно-адресної пам'яті в одну одиницю програмно-адресної пам'яті або розділити одну одиницю апаратно-адресної пам'яті на кілька одиниць програмно-адресної пам'яті.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.