Искусство программирования на Си (984073), страница 16
Текст из файла (страница 16)
Ф~'; К'".~.","~'-"";,.з " ы'," ' 'й е ',"' ж "'"';,ежек ";;,' ;,, н"''т -'-*,,Ф*'...:„-'Пь,з"*;, ...-,...', '*, ф',,"„,71;=' ;:а-;,*„.„;;.ы ;.""ъ,!„"Ам за„,'*мь,'*мь,'*мь,'*мь й,ь 44 ая Пересмагнренний нгмк С Игрн с битами и бийтаии $ ° Масть ! Глава 5 ° Результат изменения именно знакового бита суше- на степень двойки не всегда применим к отрицательным вход поступает некоторая совокупность битов, и на сокрашение 0-Х. В языке С сушествует правило, что ственно отличается в различных представлениях — числам, хотя этот способ осуществим для прсдставле- выходе также получается совокупность битов. Естс- если результат операции с величинами без знака выхокак пример можно рассмотреть битовыс комбинации ний "дополнение до двух".
ствснно, они рассматриваются в понятиях аевичин (на- дит за пределы, допустимые для типа без знака, то рс- 01111!11 и 11111111 в табл. 5.2. Подобно тому, как операцию сдвига влево можно пример (см. табл 5.3), выражение 9ь19 должно давать зультат уменьшается по модулю на МАХ-ь1, где МАХ— использовать для умножения на степени 2, операцию в результате число 28, каким бы битовым набором это это максимальное значение, которос может быть прсдОдним словом, если в битовых операциях появлясдвига вправо можно использовать для леления на стс- число ни было представлено).
В частности, для опера- ставлено в этом типе. "Уменьшить по модулю" — знаются отрицательные числа, появляются и проблемы. пени 2. Сдвигаемые за правый край биты теряются, что ций с целыми величинами без знака можно точно оп- чит, прибавить или отнять МАХ+1 столько раз, сколь- Конечно, мохсно использовать целочисленные типы со соответствует отбрасыванию остатка от деления. Как и ределить, какие битовые операции необходимо выпол- ко необходимо, чтобы вернусь величину в допустимые знаком и ограничиться положительными входными и ранее, все проходит гладко с положительными величи- нить, чтобы получить правильныи результат.
пределы. Если опять посмотреть натабл. 5лХ можноувирсзультируюшнми величинами. Олнако всегда безопаснами, чего нельзя, к сожалению, сказать об отрицатель- Рассмотрим для этого три простых случая: деть, что это произошло с результатом выражения нее придерживаться типов без знака. Одно предупреждение: величины типов айаг и зйог! преобразуются, по ных.
В дополнение ко всем проблемам представления ° Добавление 1 (инкрсмснт) 201т211. Поскольку результат (412) превосходил МАХ величин сдвиг вправо создает новую проблему: что под- (255), была вычтена величина МАХч! (256) и получснкрайнсй мере, в !и! перед любыми операциями с ними. стаалять с левого края? В случае положительных чисел ный результат (156) оказкзся в допустимоле диапазоне. Это значит, что, даже сели операция начиналась с типом без знака, вроде ыыз(Выем сйаг или ывв!Введ вйог(, ответ прост: приписываем нули, и это дает ожидаемый ° Инвертирование величины (перемена знака) В табл.
5.4 приведено сшс несколько подобных пр>гмерезультат. В случае отрицательных чисел все нс так (юв. закончиться она может величинами типа (ы! (т.е. всли- При добавлении 1 к двоичной величине излгеггсння просто Для представлений "дополнение до единицы" и чинами со знаком). В частности, если в операциях сдвига начинаются с млалшего бита. если его значение было Таблица 5.4. Уменьшение по модупю величин "дополнение до двух" компилятор может сохранить изменения данных заденут знаковый бит, это может О, оно изменяется на 1 и процесс прекрашается.
Если без знака. правильность деления при добавлении слева 1. При депривссти к неожиданным результатам. первоначальное значение было 1, то оно изменяется на ленин с остатком это вызывает округление в меньшую Истаевав величина Результат О, и затем изменения переходят на слелуюший бит бо- Игры г битачи и биитачи ! Глава 5 Ну достаточно теории; рассмотрим теперь некоторые примеры практического применения битовых и байтовых операций, а приведенные выше выражения лзы используем позже. число, поэтому общая структура данных лля хранения битового массива — это массив элементов ВАКК ЕЕТУРЕ.
Далее мы можем определить некоторые полезные относящиеся к массиву величины, которые могут использоваться другими макросами, например: вдвеьпв ВАВВ Е1В1ТВ (ОНАВ В1Т * и1квоя (ВАВВ ЕЬТТРЕ) ) Злесь ВАКК ЕЕВ!ТЯ определяет число битов в элементе массива, т.е. число битов в обьекте ВАКК ЕЕТУРЕ Его можно определить, умножив размер в байтах на число битов в одном байте (СНАК В!Т, которое определено в стандартном заголовке чйш)(в.Ь>).
Строго говоря, необходимо знать число битов в типе, которые используются для хранения величины. Поскольку все типы, кроме ввв!евед сйаг, могут содержать неиспользованные биты, полученное число битов может быть завышенным. Тем не лзенее, можно просто установить, ',роийиАиКК,„.ЦТУРиЕ,опойдслясгся как,тип, в котйайх„ В языке С нс существует никакого встроенного механизма доступа к отдельным битам, которые собраны в массив. Однако, используя битовые операции С, можно с помощью нескольких простых макросов имитировать битовые массивы. Чтобы эмулировать битовый массив, нсобкодимо следующее: х 10010000 -х 01101111 (-К) и 1 01110000 ° Возможность создавать и уничтожать объекты с битовыми полями.
Это может быть сделано либо путем прямого объявления их, либо путем создания их диналзически и использованием шайос и подобных ВАВА ЕЬТТРЕ *Ьзкв ву гт,*-з,."*,"-и' г'-,тйа(;,.'"'""зг'"',г,"'-'„'%...,'.", (эз ' "','' (Ь "к' к з, в г .'" 11 а (1 ",, "„г"; Пгргсмитрчикыи язык С Ш3- !! Часть 1 Одним словом, выражение МАХ-Х вЂ” это лругой способ записи операции -Х, а -Х (описываемое вырюксние (МАХ-Х) ь() эквивалентно (-Х)+1.
Этот результат нельзя назвать неожиданным, поскольку таким образом определяется инвертирование в представлении "дополнение ло двух". А мы уже знаем, что битовые лсйствия прн арифметических операциях величин без знака и в представлении "дополнение ло двух" соответствуют друг пруту. В общем случае инвертирование величины без знака на битовом уровне заключается в инвертировании всех битов более высокого порядка, чем младший бит 1 числа.
Это яснее видно на следующем примере Обратите внимание на позицию, которую занимает младший единичный бит в исходной величине Х. В результирующей величине этот бит сохраняет значение 1, все биты справа от него остаются нулями, а все биты Битовые массивы (битовые карты) ° Структура ланных. в которой может храниться би товый массив. :;-.": Ап.,'-*пз,"з „:":.-„.:,"(г,:„~""",).
1"!*.;": Символ зз в конце первой строки — это стандартный в языке С способ соединения строки в одну, что позволяет разместить л<акроопределенис в нескольких строках. Заметим, что объем пространства, выделяемого птайосО, задается в байтах, поэтому нужно заказать число элементов ВАКК Е1ХУРЕ в массиве, умноженное на число байтов в каждом элементе ВАКК ЕЕТУРЕ.
Нет необхолимости приводить тип величин, возвращаемых функцией шайосО, и вообще, этого нс стоит делать, поскольку это может помешать компилятору диагностировать ошибку вызова пийосО без включения <з(611Ь.Ь>. Но в этом случае приведение типов оказывается полезным, поскольку оно гарантирует, что использующая макрос программа присвоит результат переменной подходящего типа. Вы сами можете выбирать, использовать операцию приведения типа или нет. Чтобы использовать этот макрос, можно написать, например, так: :;;:1'";о - *'.
"..*, (й:,гце(„":йг.ь "*" .".. 1, *-.:,":*.':;;Ьгг; ут ! Пересмотр«нный н«ык Г Игры с йчтачи и Пачтачи ! Часть ! Глава 5 ««(пткпп ВАВВ С1.ЕАВАВВАТ (Ьпгг, И) ВАКК ТЕБТ проверяет, установлен ли [Ч-й бит в Листинг 5.1. Определения в Ытаггау.ь. тп апг(Ьаг, О, ВАВА Авялтягге(И> * ( > Ьал. Если значение бита 1, он возвращает нснулсвос Гуредег ппагяпец сЬаг ВАВВ ЕЬттуе[ а 1гчы«Х (ВАВВ ЕЬТтРЕ) ) значение, в противном случае — нуль. Операция дсй- «Впттпп ВМВ ЕЬВття (СВМ ВГТ * агапоцВАМ ЕЬтт >1 — грация дсй * ТРВ При этом требуется, чтобы вызывающая процсдура ствуст полобно макросу ВАКК БЕТ, за исключснисм «Цп(гпа ВМЕ Иалтвггв(И> [([И) + ВАЕЕ ЕЬВттЯ-1> Г ВИа ЕЬВттЯ> определяла разл1ср массива в битах.