Что такое CHAR_BIT?
Цитирование кода для вычисления целочисленного абсолютного значения (abs) без перехода от 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
и как это использовать?
3 ответа
Вы должны знать, что этот код зависит от определяемого реализацией поведения правильного сдвига битов для подписанных типов. 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
во время сборки в зависимости от вашей платформы.
CHAR_BIT
это количество бит в char
, В наши дни почти все архитектуры используют 8 бит на байт, но это не всегда так. Некоторые старые машины имели 7-битный байт.
Это можно найти в <limits.h>
,
Попытка ответить как на явный вопрос (что такое 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.
* Как правило, но не всегда то же самое, что наименьшая единица памяти, на которую может обращаться аппаратное обеспечение. Реализация может потенциально объединить несколько единиц памяти с аппаратной адресацией в одну единицу памяти с программной адресацией или разделить одну единицу памяти с аппаратной адресацией на несколько единиц памяти с программной адресацией.