Школа
программирования 174)
Программирование на Си и С++: Побитовые операторыПисьмо. Здравствуйте
уважаемый Сергей Бобровский! Меня зовут Сергей. Программированием я занимаюсь
2,5 года, и два года я писал программы на Visual Basic, не решаясь взяться за
другие языки программирования. Хочу поблагодарить вас за то, что я смог
научиться программированию ещё на двух языках за 3 месяца по вашим рассылкам
"Базовый курс" и "Программирование на С++ с нуля". Подобных
рассылок в Интернете нет и это чистая, правда! Благодаря даже небольшому знанию
C++ можно программировать 3D игры. Для этого даже движок писать не надо - в
Интернете есть бесплатные исходники таких игр как Half-life (1). Изучив один из
ваших последних уроков про наследование классов, я смог написать для этой игры
новое оружие - нож сделав его из класса монтировки и всё почти с нуля!
Рассказывайте, пожалуйста, побольше про классы - ведь на них держится всё
современное игровое программирование вот реальный заголовок класса автомата из
Half-life(думаю это покажется интересным): class CMP5 : public
CBasePlayerWeapon //Обьявляем класс автомата из оружий игрока
{
public: //Глобальные
void
Spawn( void ); //Процедура загрузки на карту
void Precache( void ); //Процедура
прекиша (кеша перед загрузкой)
int
iItemSlot( void ) { return 3; } //Функция слота интеджер
int GetItemInfo(ItemInfo *p);
//Функция инфы об оружии интеджер
int AddToPlayer( CBasePlayer *pPlayer ); //Функция добавления к
игроку если взял true если нет false
void PrimaryAttack( void );//Процедура первичной
аттаки
void SecondaryAttack(
void ); //Процедура вторичной аттаки
int SecondaryAmmoIndex( void ); //Функция значения
вторичной амуниции
BOOL
Deploy( void );//Функция взятия в руки булеан
void Reload( void );//Процедура
перезарядки
void WeaponIdle(
void ); //Процедура бездействия
float m_flNextAnimTime; //Функция флоат
int m_iShell;
private: //Локальные
unsigned short m_usMP5;
};
А ведь ещё
месяц назад я думал, что этот код только для красоты. На тех же классах
держится великая игра Half-life 2, это значит теперь я смогу редактировать
такие продвинутые игры! Мне хотелось бы спросить: что делают эти
операторы:
<<,>>, &=, ^=, |=,<<= ?
Их я нашёл в этих исходниках, но незнаю что они делают.
Расскажите, пожалуйста, о них я думаю, может ещё кому-то понадобиться.
P.S. Хорошие курсы программирования легко отличить от плохих: если
преподаватель говорит что язык сложный, вы тупой а он один умный - то это
однозначно плохие курсы и вас там ничему не научат, а если говорить о пользе
программирования, разговаривает с учениками, вдохновляет их и говорит, что
ничего сложного в программировании нет - то это великий мастер и он научит вас
всем премудростям написания программ.
Безусловно, ведь игра - это объектная надстройка, оболочка над движком, которая
как раз и рассчитана на редактирование, совершенствование и развитие. Да и
трехмерные движки сегодня тоже делают объектными, чтобы ими было удобно
пользоваться. Описание класса обычно отделяется от
реализации входящих в него методов, чтобы не смешивать интерфейс и реализацию.
Обычно структура класса выполняется в некоем стандартизованном виде - так, в
данном примере видно, что каждая переменная для наглядности имеет свой префикс.
Например, m_usMP5 - первая буква m означает member (член класса), далее следует
упоминание ее типа (us - первые буквы unsigned short), и лишь потом название.
Это древняя практика Microsoft, еще 10-15 летней давности, которой она
рекомендовала придерживаться при использовании Microsoft Visual Studio, однако
в последних версиях для .NET, если не ошибаюсь, от этой практики решено отойти.
Вообще, изучать исходные тексты профессиональных
проектов очень полезно! Такой опыт весьма позитивен. Побитовые операции В языке
С++ существуют так называемые побитовые операции - они выполняют некоторую
операцию над парами битов двух операндов. Любое значение, как известно,
представляется в компьютере в двоичном виде (в двоичной системе счисления, в
отличие от общепринятой десятичной) - то есть записывается только с помощью
двух цифр, нуля и единицы. Так, двойка запишется как 10, десятичное число 10 -
как 1010. Лирическое отступление про двоичные
числа Как и в любой системе счисления, число в
двоичном формате переводится в десятичный вид умножением каждого разряда на
соответствующую степень двойки. Например, 1010
(двоичное) =1*2-в-кубе + 0*2-в-квадрате + 1*2-в-первой-степени +
0*2-в-нулевой-степени = 1*8 + 0*4 + 1*2 +0*1 = 10 десятичное Но вдобавок к этому каждое значение хранится в памяти в
отведенной ему ячейке, размер которой кратен одному байту (восьми двоичным
разрядам или восьми битам). Минимальный размер ячейки - один байт. Современные
32-разрядные процессоры ориентированы на обработку, как явствует из их
названия, на ячейки длиной 4 байта (4*8 битов = 32 разряда). Более современные
64-разрядные модели обрабатывают, соответственно, ячейки длиной 8 байтов.
Конечно, они способны обрабатывать и отдельные
байты, однако эффективнее всего процессоры работают с ячейками, совпадающими по
разрядности с их базовой архитектурой. Такие ячейки называют машинные слова.
То есть машинное слово 32-разрядного процессора -
это ячейка размером 4 байта. Первые микропроцессоры
работали с восьмиразрядными словами, то есть с отдельными байтами. Язык Си был
разработан как раз в те времена, поэтому, хотя он исходно ориентировался на
разные аппаратные архитектуры и считался железо-независимым, исходно в него
неформально была включена поддержка 8-разрядных слов в виде типа char. Это двоичное восьмиразрядное число: 10010011 Это - тоже: 00000001 Языки
Си/С++ допускают операции над отдельными двоичными разрядами чисел. Например, есть два числа, представленые в двоичном виде:
00000001 и 00000010. Для них допустимы операции логического (побитового)
сложения (символ | ), логического умножения (символ & ) и логического
исключающего сложения (символ ^ ). Операция | (ИЛИ)
действует так - результатом будет 1, если хотя бы один аргумент равен 1.
Операция & (И) действует так - результатом будет 0, если хотя бы один
аргумент равен 0. Операция ^ выполняет так называемое исключающее ИЛИ
(xor). Он выдает 1, если операнды не равны, и 0, если равны. Эта операция
интересна тем, что, применив ее два раза к некоторому числу (точнее, сначала к
исходному числу, а затем к его xor-версии) с заданным аргументом, мы получим
исходное число. Поэтому операция XOR часто применяется в компьютерной графике -
для быстрого перемещения спрайтов по фону (два раза накладываем маску спрайта
на фон - и фон остается исходным), а также в криптографии для быстрого
шифрования (взламывается, впрочем, это шифрование тоже очень быстро :-). Тогда 00000001 |
00000010 = 00000011 00000001 & 00000010 = 00000000 00000001 ^ 00000010 = 00000011 - применяем xor к числу 00000001
... 00000011 ^ 00000010 = 00000001 - теперь с тем же ключом
00000010 применяем xor к промежуточному результату, и получаем исходное число
00000001
Аргументы не обязательно
записывать именно в двоичном формате (да и нету в С++, если не ошибаюсь,
возможности записи чисел в двоичном виде? только в десятичном,
шестнадцатеричном и восьмеричном) - компилятор все равно преобразует любые
форматы во внутренний машинный вид (двоичный :-). Поэтому предыдущие примеры
можно переписать так:
1 | 2 = 3 (числа в десятичной системе счисления)
1 & 2 = 0 1 ^ 2 = 3 3 ^
2 = 1
В некоторых случаях, однако, в
результате применения побитовых операций неожиданно может получиться
отрицательный результат. Он зависит от выбранного типа данных. По умолчанию
типы int и char хранят знаковые числа. В качестве знака числа используется
старший (самый крайний левый) бит числа. Если он равен единице, значит число
отрицательное. Тип char традиционно определяет
значения в диапазоне от -128 до +127. Это один байт. Существует также вариант
беззнаковых (неотрицательных) целых - когда перед названием типа ставится
ключевое слово unsigned (беззнаковое). Подобные числа считаются всегда
положительными, и старший бит задействуется в качестве элемента значения, а не
его знака. Например, unsigned char задает диапазон от 0 до 255. Битовые операции обычно проводят над беззнаковыми целыми,
чтобы в результате не возникало путаницы со знаком. Например: unsigned
char b1 = 1, b2 = 2, br; br = b1 | b2; // br равно 3
Существуют также операции побитового
сдвига >> и << . Они сдвигают двоичную запись числа вправо или
влево на заданное число разрядов (битов). Например:
00000001
<< 3 = 00001000 // сдвиг влево на три позиции
00000010 >> 1 = 00000001 // сдвиг вправо на одну позицию
При этом новые, - появляющиеся, разряды
всегда заполняются нулями, а исчезающие разряды никак не
"компенсируются" в значении числа. Сдвиг
вправо на несколько разрядов можно, очевидно, использовать как деление на
степени двойки. В самом простом случае сдвиг числа
вправо на один разряд можно считать делением на два:
unsigned int N; N = 8;
N = N >> 1; // поделили N на два
Умножать на два сдвигом влево тоже можно, но здесь существует опасность пропажи
старших разрядов, которые "уезжают" влево за пределы числа, и
значение искажается. Такой прием деления можно
довольно часто встретить в исходных текстах известных программ. Дело в том, что
поразрядный сдвиг выполняется значительно быстрее, нежели операция деления,
поэтому он часто задействуется в программах, где быстродействие и работа с
отдельными битами весьма важны. Это, например, всевозможные системные утилиты,
различные графические движки - немудрено, что там распространены побитовые
операции! А различные операции, побитовые И / ИЛИ, часто использовались,
когда компьютеры были совсем маленькими (по своим ресурсам, обратно
пропорциональным их размерам :),и объем оперативной памяти составлял десятки
или сотни килобайтов. Тогда приходилось экономить даже не байты, а отдельные
биты, хитроумными способами упаковывая информацию в отдельные разряды. Но
в рядовых прикладных задачах, где скорость непринципиальна (одна секунда или
две, какая разница), да и объем оперативной памяти непринципиален (несколько
десятков лишних мегабайтов ничего не изменят), побитовые операции сегодня
практически не используются, потому что их результат не всегда предсказуем, да
и код получается плохо наглядным. Но знать побитовые
операции надо :) Существуют сокращенные записи всех
упомянутых пяти операций, ориентированные на оператор присваивания. Как принято
в Си, форму присваивания с операцией О : переменная
= переменная О значение; можно переписать более
компактно (при условии, что имя переменной одно и то же): переменная О= значение; То есть
запись X
= X | 10;
допустимо записать в
сокращенном виде:
X |= 10;
Это правило
относится и к другим побитовым операциям: X = X & 10;
запишется как X &= 10;
X = X ^ 10;
запишется
как X ^= 10;
X = X >> 2;
запишется как X >>= 2;
X = X << 1;
запишется как X <<= 1;
(c) 2004-2007
Сергей Бобровский : bo собака russianenterprisesolutions.com Школа программирования с нуля Все предыдущие выпуски
базового курса всегда тут: http://www.infiltration.ru/p/ Неофициальный сайт поддержки (со срочными вопросами -
сюда): www.prog-begin.net.ru. Мои книги (учебные курсы) "Технологии Delphi /
C++ / C#. Разработка приложений для бизнеса".
http://shop.piter.com/display.phtml?a_id=17681&web_ok=all Все эти учебные курсы рассчитаны не только на
разработчиков, но и на всех тех, кто хочет стать ИТ-менеджером. Для
этого как минимум нужно иметь общее представление о современных технологиях
разработки и их истории и владеть соответствующей терминологией. Именно это мои
книги и дают. В учебных курсах описаны десятки технологий, каждой из
которых посвящены отдельные книги. Таким образом, купив один учебный курс, вы
существенно сэкономите :) В книгах полностью описаны: - Delphi (версия
2006, полностью совместимая с Delphi 2005/2006/2007 и Turbo Delphi) для обеих
платформ - Win32 и .NET; - C# (новый язык Microsoft, на котором
базируется платформа .NET и все новые версии Windows); - C++ для
платформы Win32. Охвачены также темы работы с файлами на этих платформах,
создания файл-серверных, клиент-серверных, распределенных приложений,
веб-программ (Indy, ASP.NET, веб-сервисы). Описаны языки SQL и OCL. Немало глав
посвящены истории программирования и различных технологий. Особое внимание
уделено созданию программ с помощью технологии ECO и языка моделирования UML -
программы фактически рисуются, и теперь даже для создания корпоративных
приложений и их переноса в Интернет не обязательно знать программирование! Отдельная часть отведена технологиям организации групповой работы,
управления требованиями, контроля версий, локализации и тестирования. Тут
подробнее про книги. Мои книги, которые пока
доступны в продаже: Дизайн
рассылки: Алексей
Голубев - Web-дизайн и web-программирование
|