• СТАТЬЯ  GDI+ Часть 1. Краткое знакомство
  • ВОПРОС – ОТВЕТ  Как вставлять в программу на C++ двоичные константы?
  • Программирование на Visual C++

    Выпуск №57 от 23 декабря 2001 г.

    Здравствуйте, дорогие подписчики!

    Опять я к сожалению заставил вас недоумевать, почему не выходит рассылка. Дело в том, что мне по личным причинам пришлось срочно поехать в другой город и пробыть там две недели. Выпускать рассылку оттуда в это время не было никакой возможности. Само собой разумеется, что теперь рассылка будет выходить вовремя. Я искренне прошу прощения и надеюсь на ваше понимание. Ну а теперь – к делу! Ведь за это время на сайте RSDN появилось много интересного…

    СТАТЬЯ 

    GDI+

    Часть 1. Краткое знакомство

    Автор: Виталий Брусенцев

    Демонстрационное приложение на C++ (требует наличия GDI+) – 88 Кб.

    Демонстрационное приложение на C# (требует CLR) – 62 Кб.

    За последний год компания Microsoft подготовила разработчикам множество сюрпризов. Новые продукты и технологии буквально завладели вниманием околокомпьютерного мира. Пока неясно, насколько успешным будет дебют технологии .NET и основанных на ней программных продуктов и средств разработки. Но одно из новшеств, безусловно, уже завоевало признание разработчиков, связанных с графикой и мультимедиа, – технология GDI+. Именно она, вернее, основанный на ней новый графический интерфейс является "лицом" новых операционных систем – Windows XP и .NET Server. 

    Что же такое GDI+? Официальная документация скромно называет ее Class-based API, то есть основанным на классах интерфейсе прикладных программ. Так как она встроена в Windows XP и .NET Server, ее называют частью этих операционных систем. Часто встречается также определение "библиотека" или "библиотека классов". В действительности, предоставляемый GDI+ набор классов является тонкой оболочкой над множеством обычных функций, реализованных в одной динамической библиотеке GdiPlus.dll. В общем, имея все это в виду, будем для краткости далее называть ее просто библиотекой. 

    Итак, GDI+ – это библиотека, призванная заменить существующий уже больше 11 (или 18 – как считать) лет интерфейс GDI, являющийся графическим ядром предыдущих версий Windows. Она сочетает в себе (по крайней мере, по замыслу) все достоинства своего предшественника и предоставляет множество новых мощных возможностей. Кроме того, при ее проектировании заранее ставилась цель наименее болезненного переноса приложений на 64-битные платформы. Следовательно, хотя существующие GDI-приложения будут выполняться на новых версиях Windows, для новых проектов следует использовать GDI+.

    Заглянем "под капот" Что новенького?

    Далее мы еще будем рассматривать специфические (и такие эффектные!) возможности GDI+. Здесь же только опишем основные новшества.

    Достоинства C++ – реализации:

    • Объектно-ориентированный интерфейс: благодаря поддержке компилятора C++ мы "бесплатно" получаем контроль над типами и временем жизни объектов.

    • Прозрачное управление памятью: объекты ядра GDI+ создаются в куче с помощью собственного менеджера памяти прозрачно для программиста.

    • Использование перегрузки имен функций: функции одного назначения различаются только по своим параметрам.

    • Собственное пространство имен: позволяет использовать понятные имена типов – такие, как Rect, Pen и Matrix – без конфликтов с другими библиотеками.

    • Перегрузка операторов: предоставляет удобные операции '+' и '-' для таких типов, как Point и Size.

    Архитектурные новинки библиотеки:

    • Аппаратная абстракция: как уже было замечено, упрощается перенос на 64-битные платформы.

    • теперь можно не бояться "оставить выбранной кисть в контексте перед удалением" – такая типичная для GDI ошибка! Новый дизайн графических функций/объектов:

    • Разделение функций закраски и отрисовки: предоставляет большую гибкость в рисовании, например, позволяет заливать незамкнутые фигуры.

    • Появление графических контейнеров: контейнеры позволяют "сцепить" вместе несколько операций и использовать как одну команду.

    • Увеличившаяся поддержка путей (paths) и их взаимодействия с регионами: теперь пути являются полноправными объектами вне контекста рисования и могут легко трансформироваться в регионы.

    Новые технологии и возможности (задержите дыхание):

    • Градиентная закраска: позволяет заливать сложные фигуры оттенками с различными законами распределения цвета, рисовать векторные примитивы (например, линии) с градиентной окраской.

    • Поддержка прозрачности: можно создавать кисти и растры с прозрачными и полупрозрачными областями, заливать области полупрозрачным цветом, назначать Color Key для растрового изображения и работать с его альфа-каналом, а также рисовать полупрозрачные (!) векторные примитивы и текст.

    • Режимы улучшения изображения: позволяют значительно улучшить пользовательское восприятие за счет сглаживания контурных неровностей (antialiasing) и префильтрации растровых изображений.

    • Сплайны: кроме уже существующих в GDI кривых Безье, поддерживается новый вид кривых – так называемые сплайны, которые имитируют поведение натянутой и изогнутой стальной полосы. Сплайны являются гладкими кривыми.

    • Пути: как уже говорилось, пути теперь существуют независимо от контекста рисования и представляют собой мощное средство создания сложных векторных объектов. Кроме того, появилась возможность выравнивать (flatten) пути, то есть преобразовывать их к набору отрезков прямых.

    • Координатные преобразования: объект Matrix позволяет осуществлять операции поворота, переноса, масштабирования и отражения объектов GDI+.

    • Регионы: в отличие от GDI, регионы теперь не привязаны к координатам устройства и подчиняются координатным преобразованиям.

    • Работа с растрами: теперь можно практически все! Поддерживается отрисовка растров с наложением внешнего альфа-канала, масштабированием, растяжением, искажением и поворотом растров. При этом можно установить режимы отображения отдельных пикселей – от простого переноса до префильтрации (наилучшее качество изображения). Стало возможным рисовать векторные примитивы, залитые текстурами (!).

    • Поддержка популярных форматов графических файлов: необычайно приятное новшество для всех программистов, имеющих дело с разными графическими форматами. Поддерживаются форматы BMP, GIF, TIFF, JPEG, Exif (расширение TIFF и JPEG для цифровых фотокамер), PNG, ICON, WMF и EMF. Декодеры различных форматов выполнены с учетом их специфики, так что Вы сможете, например, отобразить анимационный GIF или добавить комментарий к TIFF-файлу. Загруженный, созданный или модифицированный файл может быть сохранен на диск в одном из подходящих форматов. Существует возможность написания собственных декодеров.

    • Формат EMF+: разумеется, все это великолепие не могло уместиться в тесные рамки старого Enhanced Metafile. Для описания новых возможностей был создан новый формат метафайла EMF+, который позволяет сохранить на диск и затем проиграть последовательность графических команд. Существует возможность записать "дуальный" метафайл, понятный старым GDI-программам. Новые программы будут читать из него GDI+ – информацию.

    Требования к среде выполнения

    Поддержка GDI+ встроена непосредственно в операционные системы Windows XP и .NET Server. Для того чтобы приложения, использующие эту библиотеку, выполнялись на предыдущих версиях Windows, необходимо установить дистрибутив gdiplus_dnld.exe размером около одного мегабайта. Найти его (и, возможно, другие необходимые обновления) можно на сайте Microsoft по адресу:

    http://www.microsoft.com/msdownload/platformsdk/sdkupdate/psdkredist.htm

    В его состав входят только инструкция по установке и уже упомянутая динамическая библиотека GdiPlus.dll, которую необходимо скопировать в системный каталог Windows 98/ME, Windows NT SP6 или Windows 2000. При этом возможности, предоставляемые непосредственно ядром Windows XP (в частности, технология ClearType для качественного отображения шрифтов на LCD-мониторах), будут недоступны.

    ПРИМЕЧАНИЕ

    Я не случайно не упомянул про Windows 95. На сайте Microsoft отсутствует всяческое упоминание о поддержке GDI+ для этой операционной системы. Тем не менее, единственная доступная мне для тестирования машина с Windows 95 OSR2 выполнила тестовое приложение без каких-либо проблем. Но ввиду отсутствия какой-либо официальной поддержки для использования GDI+ крайне рекомендуется обновить систему хотя бы до Windows 98.

    Поддерживаемые технологии разработки

    В этой статье рассматривается интерфейс к GDI+, реализованный для языка C++ – хотя уже существует реализация Microsoft для системы CLR, входящей в состав .NET, и, безусловно, вскоре усилиями энтузиастов появятся другие (например, для VB и Delphi).

    Заметим, что GDI+ (вернее, ее обертка для CLR), входящая в состав Microsoft .NET Framework SDK, является основным средством рисования в среде .NET. Однако доступная на данный момент Beta 2 имеет довольно большие отличия от реализации для C++ (не только архитектурные, но и чисто внешние, например, различающиеся имена некоторых классов). Я постараюсь коротко описать эти отличия в конце статьи.

    Набор заголовочных файлов (headers) и библиотека импорта GdiPlus.lib, необходимые для сборки демонстрационных приложений, входят в состав последнего Platform SDK. Те, кто до сих пор не обновил идущий с Visual Studio 6.0 Platform SDK образца 1998 года, могут загрузить его с сайта Microsoft по адресу:

    http://www.microsoft.com/msdownload/platformsdk/sdkupdate/

    Минимальный компонент, в состав которого входит GDI+, называется Windows Core SDK и имеет размер около 230 мегабайт.

    ПРИМЕЧАНИЕ

    Я понимаю, что для многих читателей, имеющих доступ в Интернет через домашний модем, предложение скачать дистрибутив такого размера прозвучит как насмешка. В качестве крайней временной меры можно раздобыть только набор заголовочных файлов GdiPlus*.h, BaseTsd.h и библиотеку импорта GdiPlus.Lib из нового Platform SDK. Но гарантировать работоспособность такого решения во всех ситуациях я не возьмусь. Да и в любом случае, обновить Platform SDK необходимо. Возможно, вам удастся найти его на CD-ROM.

    На момент написания этих строк доступна версия Platform SDK за август 2001 г.

    Демонстрационные примеры будут в подавляющем большинстве написаны с использованием Windows API, что позволит сосредоточиться на использовании GDI+. Но вы без труда сможете подключить эту библиотеку к своим MFC– или WTL-приложениям. Иногда я также буду приводить соответствующий пример на C# для WinForms.

    Начинаем работу Иерархия классов GDI+

    Типичное рабочее место программиста на C++, как правило, включает в себя стену, на которой гордо красуется Диаграмма классов (неважно каких). Теперь рядом можно наклеить еще один плакат.

    Ниже приведена иерархия классов GDI+. Я не включил в нее 8 структур данных и перечисления (enumerations) – около 50 штук.

    Иерархия классов GDI+


    При первом взгляде на диаграмму видно, что она очень напоминает, например, ту часть библиотеки MFC, которая отвечает за рисование, только классов гораздо больше (40 против 15 у MFC). Это и неудивительно, учитывая фирму, которая разрабатывала эти библиотеки. Основные отличия отражают новые возможности GDI+. Мы подробно рассмотрим их в следующих частях.

    Как видим, большинство объектов имеют в корне иерархии класс GdiPlusBase. Вам не понадобится создавать экземпляры этого класса, так как он содержит только средства управления памятью (для него перегружены операторы new/new[] и delete/delete[], которые используют функции GDI+ GdipAlloc и GdipFree). Все классы, инкапсулирующие работу с ресурсами GDI+, порождены от GdiPlusBase. Это не значит, что их экземпляры нельзя создавать на стеке – напротив, так даже удобнее контролировать время их жизни. Зато такая архитектура позволит, например, передавать указатель на созданный объект GDI+ в модуль, написанный с использованием других средств разработки, и безопасно его удалять в этом модуле.

    ПРИМЕЧАНИЕ

    Не путайте управление памятью под экземпляры классов-оберток C++, которое осуществляется перегруженными операторами new/delete, и управление собственно ресурсами GDI+, которое скрыто от разработчиков в недрах соответствующих функций, например, GdipCreateSolidFill.

    Ключевым же классом в GDI+ является Graphics (программисты на J++ вздрогнули). Именно он содержит почти две сотни методов, отвечающих за рисование, отсечение и параметры устройства вывода. Напрашивается явная аналогия с контекстом устройства (Device Context) прежнего GDI, и эти понятия действительно тесно связаны. Из четырех конструкторов Graphics два создают его из HDC. Главное отличие заключается в изменении программной модели: теперь вы не работаете с хендлом, а вызываете методы класса. Хотя программистам на MFC эта концепция уже хорошо знакома.

    Дальнейшее наследование (например, класс TextureBrush порожден от Brush) скорее отражает цели разработчиков (скрытие деталей реализации и повторное использование оберточного кода), чем инфраструктуру библиотеки, так как в inline-методах "родственных" классов просто содержатся вызовы различных функций GdiPlus.dll. Можно сказать, что Microsoft в очередной раз спроецировала обычный "плоский" API языка C на объектно-ориентированную библиотеку C++.

    Оставшаяся часть классов не имеет общего родителя и предназначена для упрощения работы со структурами данных GDI+.

    Инициализация и завершение

    Перед тем как начать использовать классы и функции GDI+, необходимо инициализировать эту библиотеку. Для этого где-нибудь в начале своей программы нужно поместить вызов функции GdiplusStartup:

    Status GdiplusStartup(ULONG_PTR* token, const GdiplusStartupInput* input, GdiplusStartupOutput* output);

    Поля структуры GdiplusStartupInput управляют различными аспектами инициализации: в частности, можно задать функцию, которая будет вызываться при возникновении ошибок, или перехватывать все обращения к функциям GDI+. Эти детали мы рассматривать не будем. К счастью, конструктор по умолчанию структуры GdiplusStartupInput выполняет инициализацию, достаточную в большинстве случаев. При этом в качестве выходного параметра output можно задать NULL.

    "Магическое значение", на которое указывает выходной параметр token, необходимо сохранить.

    Для завершения работы с библиотекой вызовите функцию GdiplusShutdown:

    VOID GdiplusShutdown(ULONG_PTR token);

    Здесь в качестве параметра и необходимо передать то самое число, которое возвратила GdiplusStartup в параметре token.

    ПРИМЕЧАНИЕ

    Вы можете вызвать GdiplusStartup и GdiplusShutdown из разных потоков, но необходимо убедиться, что вне этой пары функций никакого обращения к объектам GDI+ не происходит. В частности, будьте осторожны, объявляя глобальными экземпляры классов – ведь их деструкторы выполнятся уже после WinMain. Кроме того, как обычно, нельзя вызывать функции инициализации и очистки из DllMain, поскольку это может привести ко входу в бесконечную рекурсию или другим неприятностям.

    Создаем первое приложение

    Настало время применить все эти сведения на практике. Для этого создадим в MS Visual C++ базовое WINAPI-приложение, которое послужит полигоном для дальнейших экспериментов. Ниже для этого приведена пошаговая процедура.

    Итак, создаем новый проект Win32 Application. Выбираем опцию A typical "Hello, World!" application и нажимаем "finish". Получившееся приложение необходимо подготовить для использования GDI+. Для этого в файле stdafx.h после строки с комментарием:

    // TODO: reference additional headers your program requires here

    добавляем следующие строчки:

    #include <GdiPlus.h>

    using namespace Gdiplus;

    и в конце файла stdafx.cpp добавляем строку

    #pragma comment(lib, "GdiPlus.lib")

    Кроме того, в файле stdafx.h необходимо удалить или закомментировать строку

    #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers

    Иначе компилятор выдаст кучу ошибок об отсутствии символов MIDL_INTERFACE, PROPID, IStream и т.д.

    Если полученное в результате приложение успешно собралось, значит, мы все сделали правильно. Пойдем дальше.

    Найдем в сгенерированном основном .cpp файле нашего проекта функцию WinMain и добавим в начале ее код инициализации:

    GdiplusStartupInput gdiplusStartupInput;

    ULONG_PTR gdiplusToken;

    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    а в конце, перед оператором return, добавим код очистки:

    GdiplusShutdown(gdiplusToken);

    Готово. Наконец-то мы можем что-нибудь нарисовать. Найдите в теле функции WndProc обработчик сообщения WM_PAINT и замените следующим кодом:

    hdc = BeginPaint(hWnd, &ps);

    OnPaint(hdc, ps.rcPaint);

    EndPaint(hWnd, &ps);

    return 0;

    Теперь где-нибудь перед функцией WndProc создадим функцию OnPaint с кодом рисования:

    void OnPaint(HDC hdc, const RECT& rc) {

     // Все строки – в кодировке Unicode

     WCHAR welcome[]=L"Welcome, GDI+ !";

     // Создаем контекст рисования и устанавливаем

     // пиксельную систему координат

     Graphics g(hdc);

     g.SetPageUnit(UnitPixel);

     RectF bounds(0, 0, float(rc.right), float(rc.bottom));

     // Загружаем фоновое изображение и растягиваем его на все окно Image

     bg(L"BACKGRND.gif");

     g.DrawImage(&bg, bounds);

     // Создаем кисть с градиентом на все окно и полупрозрачностью

     LinearGradientBrush brush(bounds, Color(130, 255, 0, 0), Color(255, 0, 0, 255), LinearGradientModeBackwardDiagonal);

     // Готовим формат и параметры шрифта

     StringFormat format;

     format.SetAlignment(StringAlignmentCenter);

     format.SetLineAlignment(StringAlignmentCenter);

     Font font(L"Arial", 48, FontStyleBold);

     // Выводим текст приветствия, длина –1 означает,

     // что строка заканчивается нулем

     g.DrawString(welcome, –1, &font, bounds, &format, &brush);

    }

    В результате у нас получится примерно вот что:

    ПРИМЕЧАНИЕ

    Приведенный пример носит только ознакомительный характер. В реальном приложении, для того чтобы нарисовать растр, его, как правило, не нужно каждый раз загружать с дискового файла :). Далее я буду пользоваться созданным макетом программы для создания других демонстрационных приложений. В качестве примера рисования будет приводиться только код функции OnPaint.

    Пример WinForms – приложения с использованием GDI+

    Для того чтобы можно было сравнить рассматриваемую реализацию GDI+ с той, что используется в .NET, приведу полный текст соответствующего приложения на новом языке C#:

    using System;

    using System.Drawing;

    using System.Drawing.Drawing2D;

    using System.Windows.Forms;


    public class GraphicsForm: Form {

     public static int Main() {

      Form fm = new GraphicsForm();

      fm.ShowDialog();

      return 0;

     }

     protected override void OnPaint(PaintEventArgs a) {

      DoPaint(a.Graphics, a.ClipRectangle);

     }

     protected void DoPaint(Graphics g, Rectangle clipBox) {

      RectangleF bounds = clipBox;

      string welcome = "Welcome, GDI+ !";

      Bitmap bg = new Bitmap("BACKGRND.gif");

      g.DrawImage(bg, bounds);

      LinearGradientBrush brush =

       new LinearGradientBrush(bounds, Color.FromArgb(130, 255, 0, 0), Color.FromArgb(255, 0, 0, 255), LinearGradientMode.BackwardDiagonal);

      StringFormat format = new StringFormat();

      format.Alignment = StringAlignment.Center;

      format.LineAlignment = StringAlignment.Center;

      Font font = new Font("Arial", 48, FontStyle.Bold);

      g.DrawString(welcome, font, brush, bounds, format);

     }

    }

    Как видим, помимо чисто синтаксических отличий имеются и принципиальные, например, использование в CLR-модели свойств против использования Set-методов в C++. Кроме того, в .NET активно используются пространства имен.

    ПРИМЕЧАНИЕ

    Замечу, что здесь приведен полный текст программы, аналогичной по возможностям той, что мы создали в предыдущем разделе. Сравните объем исходных текстов этих двух примеров. NO COMMENTS.

    Если вы запустите приведенный пример, то увидите, что текст отрисовывается без сглаживания, характерного для предыдущего примера. Это связано с тем, что WinForms по умолчанию отключает улучшенный режим отрисовки шрифтов – и без этого причин для торможения достаточно :)

    Несколько замечаний о компиляции и сборке проектов

    Хочется указать на несколько "подводных камней", которые могут сбить с толку при первой попытке откомпилировать и собрать проект, использующий GDI+. В основном здесь упомянуты те проблемы, с которыми сталкиваются (и постоянно спрашивают о них в различных форумах) начинающие.

    Где взять GdiPlus.h?

    Как я уже сказал, все заголовочные файлы, библиотека импорта и документация к библиотеке входят в состав последнего Platform SDK. Они не идут в составе Visual C++ 6.0 и его сервис паков.

    Почему выдается ошибка о типе ULONG_PTR?

    Похоже, что компилятор находит старый заголовочный файл basetsd.h – например, из комплекта VC++. Измените пути поиска заголовочных файлов так, чтобы вначале были найдены файлы Platform SDK.

    Почему компилятор не дает создать объект GDI+ при помощи new?

    Такое поведение возможно при попытке откомпилировать MFC-приложение с использованием GDI+ в Debug-конфигурации.

    В начале файла программы, видимо, имеется следующий фрагмент:

    #ifdef _DEBUG

    #define new DEBUG_NEW

    #undef THIS_FILE

    static char THIS_FILE[] = __FILE__;

    #endif

    Либо откажитесь от создания объектов GDI+ с помощью new, либо откажитесь от проверок динамической памяти в этом файле (удалив вышеприведенную директиву #define).

    Не забудьте про пространство имен Gdiplus и библиотеку импорта

    В приводимых примерах кода используются простые имена классов, такие как Brush и Rect. Это стало возможным благодаря тому, что в начале заголовочного файла программы есть директива

    using namespace Gdiplus;

    Если это решение не подходит (например, в проекте уже существуют классы с такими именами), то перед именами классов необходимо ставить префикс пространства имен, например

    Gdiplus::Rect rect;

    Также, если по каким-то соображениям директива

    #pragma comment(lib, "gdiplus.lib")

    не устраивает, в опциях компоновщика нужно явно указать библиотеку импорта gdiplus.lib.

    На этом пока все. В следующей части мы рассмотрим богатые возможности, которые GDI+ предоставляет для работы с растровыми изображениями.

    ВОПРОС – ОТВЕТ 

    Как вставлять в программу на C++ двоичные константы?

    Автор: Александр Шаргин 

    В языке C++ есть восьмеричные, десятичные и шестнадцатеричные константы. А двоичных – нет. Тем не менее, при помощи препроцессора можно соорудить макрос, который позволит нам смоделировать такие константы. Основная идея – преобразовывать восьмеричную константу в двоичную, выделяя из неё отдельные цифры и умножая их на соответствующий весовой коэффициент. Есть только одна проблема: в тип long влезет не более десяти цифр, а этого хватит только на формирование двоичных констант длиной в байт. Хотелось бы иметь и более длинные двоичные константы. Чтобы решить эту проблему, можно ввести дополнительные макросы, которые будут склеивать короткие двоичные последовательности в более длинные. Эти макросы могут выглядеть примерно так. 

    #define BIN8(x) BIN___(0##x)

    #define BIN___(x) \

     ( \

     ((x / 01ul) % 010)*(2>>1) + \

     ((x / 010ul) % 010)*(2<<0) + \

     ((x / 0100ul) % 010)*(2<<1) + \

     ((x / 01000ul) % 010)*(2<<2) + \

     ((x / 010000ul) % 010)*(2<<3) + \

     ((x / 0100000ul) % 010)*(2<<4) + \

     ((x / 01000000ul) % 010)*(2<<5) + \

     ((x / 010000000ul) % 010)*(2<<6) \

     )


    #define BIN16(x1,x2) \

     ((BIN(x1)<<8)+BIN(x2))


    #define BIN24(x1,x2,x3) \

     ((BIN(x1)<<16)+(BIN(x2)<<8)+BIN(x3))


    #define BIN32(x1,x2,x3,x4) \

     ((BIN(x1)<<24)+(BIN(x2)<<16)+(BIN(x3)<<8)+BIN(x4))

    Для компиляторов, поддерживающих 64-разрядные целые, можно также ввести дополнительный макрос BIN64. Для Visual C++ он будет выглядеть так. 

    #define BIN64(x1,x2,x3,x4,x5,x6,x7,x8) \

     ((__int64(BIN32(x1,x2,x3,x4)) << 32) + __int64(BIN32(x5,x6,x7,x8)))
     

    Обратите внимание, что к параметру макроса BIN8 при помощи оператора ## принудительно дописывается ведущий ноль, чтобы с ним можно было работать как с восьмеричной константой. Благодаря этому пользователь может смело применять макрос BIN8 как к числу с ведущими нулями, так и без них, и всё будет работать именно так, как он ожидает. 

    Использовать наши макросы можно примерно так. 

    char i1 = BIN8(101010);

    short i2 = BIN16(10110110, 11101110);

    long i3 = BIN24(10110111, 00010111, 01000110);

    long i4 = BIN32(11101101, 01101000, 01010010, 10111100);
     

    Самое замечательное состоит в том, что, хотя выражения для пересчёта из десятичной системы в двоичную получаются очень громоздкими, они остаются константными, а значит будут вычисляться в процессе компиляции. Это, в частности, означает, что наши двоичные числа можно использовать везде, где требуется константа (для задания размера массива, в метках case оператора switch, для указания ширины битового поля и т. д.). 

    Реализация макроса BIN8, показанная выше, достаточно прямолинейна. Этот же макрос можно реализовать более элегантными способами. Например, вот вариант, предложенный Игорем Ширкалиным. 

    #define BIN__N(x) (x) | x>>3 | x>>6 | x>>9

    #define BIN__B(x) (x) & 0xf | (x)>>12 & 0xf0

    #define BIN8(v) (BIN__B(BIN__N(0x##v)))


    До встречи через неделю! 

    (Алекс Jenter jenter@rsdn.ru) (Duisburg, 2001. Публикуемые в рассылке материалы принадлежат сайту RSDN.)





     

    Главная | В избранное | Наш E-MAIL | Прислать материал | Нашёл ошибку | Наверх