Что такое CHAR_BIT?

93

Цитата из кода для вычисления целочисленного абсолютного значения (абс) без перехода из 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и как им пользоваться?

Дато Датуашвили
источник

Ответы:

0

Вы должны знать, что этот код зависит от определяемого реализацией поведения правого битового сдвига для подписанных типов. 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во время сборки в зависимости от вашей платформы.

R .. GitHub НЕ ПОМОГАЕТ ICE
источник
122
Я не понимаю, как это может быть принятым ответом, поскольку он не отвечает на вопрос, хотя это очень интересный комментарий.
qdii
16
@Mauris: Кто-то отредактировал вопрос и переместил подвопрос в заголовок вопроса. По общему признанию, первоначальное название было ужасным, но вопрос ОП был о том, как работает приведенный код битового взлома, и «это не так, по крайней мере, не переносимо, и вот почему» - полезный ответ.
R .. GitHub НЕ ПОМОГАЕТ ICE
12
Я понимаю. К сожалению, этот вопрос очень часто появляется в результатах поиска Google по запросу "Что есть CHAR_BIT?" , даже если это был не исходный вопрос. :( Учитывая ваше объяснение, я понимаю, почему вы написали этот ответ, но для потомков может быть более полезным либо (а) удалить свой ответ и переписать его как комментарий к вопросу, чтобы @AraK был вверху, либо (б) отредактируйте свой ответ так, чтобы он отвечал текущему заголовку вопроса.
Линн
1
Из-за разницы в намерениях исходного вопроса OP и его интерпретации редактором создается впечатление, что природа исходного запроса была изменена непроизвольно. Хотя оба вопроса (оригинальный и отредактированный) заслуживают внимания, это расхождение необходимо устранить. Теперь я спрашиваю: можно ли добавить этот ответ в вики? Это, возможно, поможет людям, которые ищут такую ​​информацию, хотя это не относится к исходному вопросу. После этого вопрос можно было бы снова отредактировать, чтобы он соответствовал первоначальной просьбе датуашвили. Просто заинтересованный читатель ...
2
Я только что посмотрел историю этого вопроса, и исходный вопрос нигде не спрашивает, как работает код. Вопрос, который редактор повысил до титула, - единственный актуальный вопрос.
plugwash 03
230

CHAR_BITэто количество бит в char. В наши дни почти все архитектуры используют 8 бит на байт, но это не всегда так. Некоторые старые машины использовали 7-битный байт.

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

Арак
источник
3
Некоторые DSP имеют 10 или более битовых байтов.
Юри Робл
64
C требует CHAR_BIT>=8и допускает гораздо большие значения для DSP, которые имеют только один размер шрифта, часто 32 бита. POSIX требует CHAR_BIT==8. В общем, вы можете предположить, что любая многопользовательская / многозадачная серверно-ориентированная или интерактивно-ориентированная архитектура имеет любую возможность подключения к Интернету или обмена текстовыми данными с внешним миром CHAR_BIT==8.
R .. GitHub НЕ ПОМОГАЕТ ICE 08
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
Йенс Густедт 08
22
@Jens Gustedt: Пожалуйста, процитируйте раздел в спецификации C99. Что касается целочисленных типов точной ширины, в спецификации C99 говорится: «Эти типы являются необязательными». (7.18.1.1/3) Однако требуются типы минимальной и максимальной ширины.
jamesdlin 08
3
@jamesdlin & caf: извини, что перепутала. да, требование, на которое я ссылался, фактически исходит от POSIX stdint.h. Таким образом, это требуется, и он также помечен как расширение стандарта ISO C , без ссылки на конкретную версию этого стандарта. Виноват.
Йенс Густедт 08
2

Попытка ответить как на явный вопрос (что такое CHAR_BIT), так и на неявный (как это работает) в исходном вопросе.


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

CHAR_BIT в C и C ++ представляет количество бит в char. Всегда должно быть не меньше 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 для самого отрицательного значения приводит к неопределенному поведению. Это можно исправить, добавив приведение типов, чтобы последняя строка программы оценивалась как целое число без знака.

* Это обычно, но не всегда, то же самое, что и наименьшая единица памяти, которую может адресовать оборудование. Реализация потенциально может объединить несколько единиц памяти с аппаратной адресацией в одну единицу памяти с программной адресацией или разделить одну единицу памяти с аппаратной адресацией на несколько единиц памяти с программной адресацией.

промывка
источник