логические операции
в разных исходниках встретил операции такого вида
variable & 0x01
и
variable & 0x80
сколько не думал, вообще ничего не могу придумать, что это может быть
я знаком с логикой, вопрос не о том, что это за операции, вопрос — что такое 0x01 и 0x80?
через 0x записываются шестнадцатиричные числа, тогда чему равно 0x80? значит это что-то другое
может кто-нибудь знает что это за числа?
#1
12:20, 17 мая 2010
Красная Звезда
> сколько не думал, вообще ничего не могу придумать, что это может быть
Это т.н. операция «мАскирования» (от слова маска) битов переменной. в тех местах, где в маске установлены единичные биты, в результате логической операции — значения битов variable будут сохранены (в независимости от того, что там было), остальные биты, там где в маске нулевые биты — будут принудительно обнулены.
> вопрос — что такое 0x01 и 0x80?
Это и есть те самые маски. соответствено
0x01 в битовом представлении это 00000001
0x80 соответственно — 10000000
Соответственно эти маски — первая позволяет обнулить все биты кроме нулевого, а вторая все биты кроме старшего седьмого (если речь идет о числах в диапазоне 0x00 — 0xFF)
#2
12:23, 17 мая 2010
школьники жгут)
сейчас не модно двоичную систему изучать?)
Это побитовое И. твои примеры просто устанавливают 0-вой и 15-й биты в variable.
#3
12:26, 17 мая 2010
Galant
> Это побитовое И. твои примеры просто устанавливают 0-вой и 15-й биты в
> variable.
мммм. еще и школотой обзывает. а не знает, что установка битов — это операция лог. ИЛИ, а вот лог. И — это как раз сброс.
#4
12:38, 17 мая 2010
ну попутал чуток от смеха)) но как написано в правилах демагога «это каждый дурак знает»))
#5
12:41, 17 мая 2010
Galant
> но как написано в правилах демагога «это каждый дурак знает»))
Если о школах речь, то информатику везде по разному преподают. где-то алгебру-логику изучают, а где-то учаться из ворда мейлы отправлять да домики с солнышками в пеинте рисовать. так что ничего постыдного в вопросе нет, — начинающим вполне простительно.
#6
12:47, 17 мая 2010
да никто никого не стыдил))
я даже могу похвалить, что человек читает исходники)) но теорию надо подтянуть всё-таки)
Красная Звезда
чему вас в школе учат?
#7
12:50, 17 мая 2010
Красная Звезда
> логические операции
это не логические операции, а битовые
#8
13:01, 17 мая 2010
ashujon
> это не логические операции, а битовые
Для каждого конкретного бита в числе — операция будет таки логической.
#9
13:07, 17 мая 2010
oistalker
термин «битовые операции» включают в себя «побитовые логические операции» — то что ты назвал, но они не равны «логическим операциям»
логические
&& ! || != ==
битовые
> ~ & | ^
побитовые логические
~ & | ^
#10
13:13, 17 мая 2010
ashujon
> то что ты назвал, но они не равны «логическим операциям»
В Булевой алгебре, а в данном топике речь только о ней, — других логических нет.
#11
14:02, 17 мая 2010
Cyclone
> & это не сброс а проверка состояния нужного бита
> сброс выглядел бы как &~
Это зависит от взгляда на маску. а сброс или проверка, — это зависит от того, для чего конкретно выполняется операция.
#12
14:05, 17 мая 2010
Ты путаешь работу с булевыми и числовыми типами в ЯВУ и собственно саму по себе алгебру логику. Хинт, — в процессоре (и языке ассемблера) нет никаких &&, ||, &~ и проч.
#13
14:12, 17 мая 2010
oistalker,логические операции для логических типов, битовые операции для численных типов, причем здесь язык ассемблера, процессор, и тем более ЯВА? это вопрос терминологии
#14
14:16, 17 мая 2010
>логические операции для булевых типов, битовые операции для численных типов,
> причем здесь язык ассемблера, процессор
Не знает процессор ни про какие типы. и при чем он из-за того, что выполняет машинный код, в который преобразует твоё творчество с типами компилятор
> и тем более ЯВА?
ЯВУ — Язык Высокого Уровня
0x01 что это за число

Битовые операции
В этой статье, я расскажу и покажу на практике как и когда можно использовать битовые операции в программах, написанных на C#. На самом деле, работу с битовыми операциями можно отнести к низкоуровневой работе, и C# программисты довольно редко испытывают подобную необходимость. Ведь действительно, большинство задач можно решить более изящными способами, но бывают случаи, когда использование битовых операций просто необходимо.
Например, в моей практике, приходилось сталкиваться с необходимостью контролировать состояние внешней системы. Вот представьте, у Вас есть какая-то система, состоящая из восьми блоков, и Вы должны постоянно мониторить состояние этой системы. Или даже так, система сама, периодически отправляет в интерфейс связи со «внешним миром» информацию о своем состоянии, а Вы подключились к этому интерфейсу и обрабатываете полученные данные. Так вот, система отправляет состояние по каждому своему блоку, причем состояние блока может быть выражено двумя значениями: блок работает и блок не работает. А информация передается не по каждому блоку отдельно (в виде логических да/нет, выражающего состояние блока) а по всем блокам сразу, в виде одного байта (восьмибитного числа), где каждый бит соотнесен с состоянием определенного блока.
Разряды чисел (в том числе и двоичные, т.е. биты) принято нумеровать начина с младшего (самого правого, в привычной записи). При чем, младшему разряду принято давать номер «0», следующий будет иметь номер «1», потом будет «2» и т.д. Вот пример числа в двоичной записи: 01101111, где старший бит (бит №7) равен «0», а младший (бит №0) равен «1».
Пусть младший бит соотносится с состоянием первого блока (или блока с индексом «0»), а старший — с восьмым блоком (или блоком с индексом «7»). Тогда, если младший бит (самый правый в привычном написании числа) установлен в «1», то мы считаем что первый блок работает, а если бит сброшен в «0», то считаем, что блок не работает. Таким образом, если система решит сообщить нам что работают все блоки кроме второго и четвертого, она пришлет такое значение: 245 в десятичной системе счисления, или 11110101 — в двоичной.
Так вот, получить это число мы получим, но его нужно еще проанализировать, тут нам и помогут битовые операции. В данном случае, для получения состояния определенного блока, нам нужно «считать» конкретный разряд, т.е. узнать значение определенного бита (чему оно рано, «о» или «1»). Выполняется эта задача при помощи операции побитового «И» (в C# обозначается как «&»), путем наложения битовой маски на полученное число: [полученное число] & [битовая маска]. Битовая маска — это тоже, какое-то число, которое мы подбираем определенным образом. А что бы понять, как правильно подобрать битовую маску, мы должны понимать, как работает операция побитового «И». А работает она следующим образом, сравниваются соответствующие биты обоих чисел (т.е. нулевой бит сравнивается с нулевым битом другого, первый — с первым, второй — со вторым), и побитово формируется результат, в виде третьего числа. Причем, если соответствующий бит первого числа равен «1» и соответствующий бит второго числа равен «1», то и в результирующим числе соответствующий бит будет равен «1», а во всех остальных случаях, в результате будет «0». И так перебираются все биты обоих чисел, и формируется результат.
Например, наложение маски 110000011 на число 11110011, т.е. (11110011 & 110000011) даст результат 11000011.
Так как же узнать значение нужного нам бита? Да легко, нужно сформировать битовую маску так, что бы нужный по порядку бит (например, самый младший) был равен «1», а все остальные биты маски были равны «0». После этого, нужно наложить маску на число с помощью операции «&», и если результат будет равен «0», то в исходном числе, интересующий бит равен «0», в противном случае (если результат отличен от нуля), бит установлен в «1».
Используя эти знания, давайте напишем класс, объекты которого будут хранить числа полученные от внешней системы и по запросу (обращению к нужному свойству), возвращать состояние интересующего блока в виде логического значения true/false. Выглядеть такой класс может примерно так:
class StateController < //Конструктор, принимает общее состояние в виде байтового чила public StateController(byte aComplexState) < state = aComplexState; >//Возвращает состояние первого блока public bool Unit1State < get < //Получить промежуточный результат, наложив маску битовую маску 00000001 на общий статус int result = state & 0x01; //0x01(в hex) это 00000001 (в bin) //Если результат равен 0 if (result == 0) return false; //Блок не работает else return true; //Блок работает (результат не равен нулю) >> //Возвращает состояние второго блока public bool Unit2State < get < //Получить промежуточный результат, наложив маску битовую маску 00000010 на общий статус int result = state & 0x02; //0x02(в hex) это 00000010 (в bin) //Если результат равен 0 if (result == 0) return false; //Блок не работает else return true; //Блок работает (результат не равен нулю) >> //Возвращает состояние третьего блока public bool Unit3State < get < //Получить промежуточный результат, наложив маску битовую маску 00000100 на общий статус int result = state & 0x04; //0x04(в hex) это 00000100 (в bin) //Если результат равен 0 if (result == 0) return false; //Блок не работает else return true; //Блок работает (результат не равен нулю) >> /*Свойства Unit4State - Unit7State не показаны для сокращения кода*/ //Возвращает состояние восьмого блока public bool Unit8State < get < //Получить промежуточный результат, наложив маску битовую маску 00000100 на общий статус int result = state & 0x80; //0x80(в hex) это 10000000 (в bin) //Если результат равен 0 if (result == 0) return false; //Блок не работает else return true; //Блок работает (результат не равен нулю) >> //Общий статус (в нем закодировано состояние всех блоков) private byte state; >
Запись вида 0x01 означает, что мы указали число в шестнадцатеричной системе счисления. Если мы хотим задать значение числа в шестнадцатеричной форме, то мы должны добавить префикс «0x» перед числом (так же, можно указывать ведущие нули).
Теперь, если мы создадим объект класса «StateController» с указанием числа полученного от системы, например, пусть это будет число 26 (в десятичной системе), то вызвав свойство «Unit1State», мы увидим, что первый блок не работает:
//Создаем объект StateController tmpCtrl = new StateController(26); //Выведет сообщение о том, что первый блок не работает. Console.WriteLine(tmpCtrl.Unit1State == true ? "Первый блок работает" : "Первый блок не работает");
В этой статье, я рассказал о том, как получать значения конкретных битов числа! В следующей статье, я продолжу рассказывать про битовые операции в C# (обсудим установку значений конкретным битам числа).
Добавить комментарий Отменить ответ
Для отправки комментария вам необходимо авторизоваться.
Представление целых чисел в GAS
Целочисленные константы могут быть представлены в виде бинарного числа, записанного в двоичной системе счисления или числа, записанного в системе счисления десятичной, восьмеричной или шестнадцатеричной .
Бинарным числом, представленным в двоичной системе счисления, предваряет 0b или 0B, и следующие за ними цифры 0 или 1.
Числом, представленным в восьмеричной системе счисления, относятся константы, имеющие впереди 0 одно и более допустимых восьмеричных чисел 01234567
К числам, представленным в десятичной системе счисления, относятся константы, имеющие впереди первую ненулевую цифру и/или следуемые за ней одно или более десятичных цифр (0123456789).
К числам, представленным в шестнадцатеричной системе счисления, относятся константы, начинающиеся с 0x или ‘0X и следуемых за ними шестнадцатеричных цифр 0123456789abcdefABCDEF.
При этом вне зависимости от используемой системы счисления, саму запись константного числа в непосредственном операнде необходимо предварять префиксом $. Иначе, оно будет определено как прямой адрес памяти, который тоже можно отнести к константному значению.
2. Использование систем счисления
В таблице 1 приводится соотношение перечисленных выше систем счисления, применяемых для представления целых чисел в константных выражениях и операциях вывода целых чисел.
| 3 бит | 2 бит | 1 бит | 0 бит | DEC | BIN | OCT | HEX |
| 0 | 0 | 0 | 0 | 0 | 0b0000 | 00 | 0x00 |
| 0 | 0 | 0 | 1 | 1 | 0b0001 | 01 | 0x01 |
| 0 | 0 | 1 | 0 | 2 | 0b0010 | 02 | 0x02 |
| 0 | 0 | 1 | 1 | 3 | 0b0011 | 03 | 0x03 |
| 0 | 1 | 0 | 0 | 4 | 0b0100 | 04 | 0x04 |
| 0 | 1 | 0 | 1 | 5 | 0b0101 | 05 | 0x05 |
| 0 | 1 | 1 | 0 | 6 | 0b0110 | 06 | 0x06 |
| 0 | 1 | 1 | 1 | 7 | 0b0111 | 07 | 0x07 |
| 1 | 0 | 0 | 0 | 8 | 0b1000 | 10 | 0x08 |
| 1 | 0 | 0 | 1 | 9 | 0b1001 | 11 | 0x09 |
| 1 | 0 | 1 | 0 | 10 | 0b1010 | 12 | 0x0A |
| 1 | 0 | 1 | 1 | 11 | 0b1011 | 13 | 0x0B |
| 1 | 1 | 0 | 0 | 12 | 0b1100 | 14 | 0x0С |
| 1 | 1 | 0 | 1 | 13 | 0b1101 | 15 | 0x0D |
| 1 | 1 | 1 | 0 | 14 | 1110B | 16 | 0x0E |
| 1 | 1 | 1 | 1 | 15 | 0b1111 | 17 | 0x0F |
Начиная со школы мы привыкли оперировать с числами в десятичной системе счисления, а вычислительная техника в двоичной, программисты же пишущие на языке GNU С/Assembler для удобства в шестнадцатеричной, потому что она позволяет легко разделить байты пополам на 4-ре бита. Восьмеричная же система счисления используется в основном для задания системными администраторами прав доступа к объектам и устройствам файловой системы, потому что позволяет разбивать данные на три бита.
Для перевода из одной системы счисления в другую можно использовать специальные калькуляторы или на основе таблицы 1, простым пересчетом выполнить расчет следующим образом.
К примеру число в двоичной системе счисления 0b1000, которое соответствует 8 в десятичной системе счисления, добавляем впереди ещё пару бит 1 и 0, получив таким образом бинарное число 0b101000. Для перевода в шестнадцатеричную систему счисления согласно таблице 1 необходимо выбрать в соответствие с состояниями единичных битов из столбца HEX для старших двух битов 2, а младших четырех – 8, что вместе составит 0x28. Для бинарного числа 0b11101000 по той же таблице получим для старших четырех битов из столбца HEX E, а младших – 8, что вместе составит 0xE2. Как видно из приведенных примеров числа четные, в то время как нечетное число будет иметь в младшем разряде всегда 1.
Теперь на основе той же таблицы произведем перевод десятичного числа 255 в двоичное. Пользуясь нехитрым правилом, что нечетное число в нулевом, младшем бите равно 1, записываем начальное константное выражение 0b1, а само десятичное число 255 уменьшая на один получая тем самым значение 254. Для определение остальных битов нам нужно, основываясь на таблице 1, построить дискретный ряд соответствующий их порядку следования в двоичной системе. Если посмотреть внимательно на десятичные значения в строках таблицы 1, имеющие одиночное значение в битах с нулевого по четвертый, они меняются строго по формуле – 2 N .
Соответственно, Бит 4 = 2 4 = 16, Бит 5 = 32, Бит 6 = 64, Бит 7 = 128. На этом остановимся, потому что единичное значение в восьмом бите равняется 256. Тем самым мы определили старший, значащий бит 7 разбираемого десятичного числа в двоичной системе отсчета и можем записать как 0b10000001.
Затем, отнимаем 128 от 254 получаем 126 и определяем для него старший бит 6, который равняется десятичному значению 64 и записываем в двоичное выражение 0b11000001. Далее, таким же образом получаем двоичные значения:
0b11100001 – 62 от 32 получим единичное значение в бите 5
0b11110001 – 30 от 16 получим единичное значение в бите 4
0b11111001 – 14 от 8 получим единичное значение в бите 3
0b11111101 – 6 от 4 получим единичное значение в бите 2
0b11111111 – 2 от 2 получим единичное значение в бите 1
В остатке мы получим нуль, подтверждая тем самым, что данный способ работает.
Теперь в соответствие с таблицей 1 переводим полученное двоичное число 0b11111111 в восьмеричную систему отсчета, аккуратно разделив его по три бита 0b11 = 03 0b111=07 0b111=07, которое в итоге равно восьмеричному значению числа 0377 и равное десятичному значению числа 255.
Для перевода в шестнадцатеричную систему счисления разделим двоичное число 0b11111111 по четыре бита – 0b1111=0xF и 0b1111=0xF и с помощью той же таблицы 1 приводим его к шестнадцатеричному значению 0xFF.
3. Размерность целых чисел без учета знака
Размерность целых чисел без учета знака определяется их размером, используемым в процессе вычислительных операций с ними в зависимости от выбранного типа данных. GNU Assembler оперирует целочисленными данными в соответствие с фундаментальными типами используемыми в архитектуре Intel x86, как показано на рис. 1
| 1 байт |
| 7 0 |
| Ст.байт | Мл.байт | 2 байта |
| 15 8 | 7 0 |
| Ст. слово | Мл. слово | 4 байта | ||
| 31 16 | 15 0 | |||
| Ст. сдвоенное слово | Мл. сдвоенное слово | 8 байт | ||||||
| 63 32 | 31 0 | |||||||
Согласно с рис.1 целые числа могут быть представлены четырьмя базовыми типами с размерностью в байт (восемь бит), слово (16-ть бит), двойное слово (32 бита), четверное слово (64 бита).
| Тип данных GNU C | Диапазон значений | Размер в x86-32, байт | Размер в x86-64, байт | Объявление в GNU Assembler |
| unsigned char | 0, … ,255 | 1 | 1 | .byte значение [, … ,значение N] |
| unsigned short | 0, … ,65535 | 2 | 2 | .hword значение [, … ,значение N] |
| .short значение [, … ,значение N] | ||||
| unsigned int | 0, … ,4294967295 | 4 | 4 | .int значение [, … ,значение N] |
| unsigned long | 0, … ,4294967295 (18446744073709551615 в х86-64) | 4 | 8 | .long значение [, … ,значение N] |
4. Порядок следования байтов
Вопрос порядка следования байт возникает при оперировании c данными, имеющий размер от двух байт и более, потому что архитектура x86 использует порядок следования отличный от того, чем мы привыкли пользоваться. В листинге 1, показан пример записи кода ассемблера в мнемоническом представлении программистом (справа) и в машинных кодах (слева) результат работы GNU Assembler AS(1).
. . . 11: 05 67 45 23 01 add $0x1234567,%eax 16: 66 05 ab 89 add $0x89ab,%ax 1a: 04 cd add $0xcd,%al 1c: 80 c4 ef add $0xef,%ah . . .
Как следует из листинга 1, 32-х разрядное целочисленное значение (без учета знака) по смещению 0x11 в машинных кодах содержит, как и полагает её типу, четыре следующих друг за другом байтов от старшего к младшему (big-endian), комбинируемые как сдвоенные слова. Такую же картину можно наблюдать с 16-ти разрядным словом по смещению 0x16, а вот данные по смещению 0x1a и 0x1с, имеющие размерность в один байт, не подвержены таким метаморфозам.
В том же листинге, слева приводится порядок запись данных – следующих друг за другом байтов от младшему к старшему (little-endian), который мы привыкли использовать со школьной скамьи.
Для конвертирования данных из формата «big-endian» в формат «little-endian» и обратно в архитектуре х86 предусмотрена инструкция BSWAP, которую так же можно использовать для повышения быстродействия вычислительных операций десятичной арифметики.
Инструкция BSWAP (от англ. byte swap – байтовая перестановка) изменяет порядок следования байтов в 32-х разрядном операнде следующим образом:
биты с 0 по 7 в нулевом байте меняются местами с битами в четвертом байте (биты 24, … ,31);
биты с 8 по 15 во втором меняются местами с битами в третьем байте (биты 6, … ,21).
В листинге 2 приводится пример использование инструкции BSWAP.
. . . imm32_value: .int 0xD4C3B2A1 . . . movl imm32_value,%edx bswapl %edx,%eax . . .
В листинге 3 приводится результат выполнения BSWAP
user@debian:~/gasrunparts-0.2$ src/gasrunparts bswap_intops Result: 0xA1B2C3D4
Для конвертирования 16-ти разрядных данных из формата «big-endian» в формат «little-endian» вместо инструкции BSWAP следует использовать XCHG, как показано в листинге 4.
. . . imm16_value: .hword 0xF2E1 . . . movw imm16_value, %ax xchgb %al, %ah . . .
В листинге 5 приводится результат выполнения XCHG
user@debian:~/gasrunparts-0.2$ src/gasrunparts xchgw_intops Result: 0xE1F2
На рис. 2 показан пример конвертирования 32-х и 16-ти разрядных данных из формата «big-endian» в формат «little-endian» в соответствие с кодом ассемблера, приводимом в листингах 2 и 3.
| $0xD4C3B2A1 | bswap | $0xA1B2C3D4 | ||||||
| D416 | C316 | B216 | A116 | → | A116 | B216 | C316 | D416 |
| $0xF2E1 | xchg | $0xE1F2 | ||
| F216 | E116 | → | E116 | F216 |
Что это значит 0x01 ?
0x01 — это такая форма для записи шестнадцатеричных чисел. В данном случае это просто 1. 0xFF — это уже 255.
Отслеживать
ответ дан 16 окт 2013 в 16:21
112k 6 6 золотых знаков 93 93 серебряных знака 159 159 бронзовых знаков
- c
- c++
-
Важное на Мете
Похожие
Подписаться на ленту
Лента вопроса
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.1.9.3159
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.