2016-01-05

Eclipse Ogre source code highlight

I have faced with problem of Eclipse a multiple times. The problem is your IDE set up correctly and binary compiled but in error window you have a bunch of errors and CodeIndex does not know where Ogre objects come from.

So my solution is:
Open Project properties -> C/C++ General -> Paths and Symbols -> Source Location (tab)

And here link Ogre include folder (for Linux it is usually /usr/include/OGRE) to your project. It should help.

Not that. Sometimes after this trick you are not able to compile your own sources. So try to remove this link (weird it helps and after all syntax highlighted as well)

P.S. You can do this trick to another sources as well. 

2013-11-22

Дружим Eclipse и OpenCV для C++

Окружение: ОС - Fedora 19 x86_64, Eclipse Platform Version: 4.3.1 Build id: 5fc19

Итак, для меня стало проблемой, как научить Eclipse понимать библиотеку OpenCV. Так что-бы работал IntelleSence.

Дело было так. С горем по полам я собирал проект, он компелировался но у меня постоянно были ошибки, типа [http://stackoverflow.com/questions/10803685/eclipse-cdt-symbol-cout-could-not-be-resolved]. Сразу оговорюсь, что не нужно делать сейчас то, что представлено в этой сслыке (попробуйте это, если вам не поможет мой метод).

Итак, к делу. Для начала рекомендую ознакомиться с [http://docs.opencv.org/doc/tutorials/introduction/linux_eclipse/linux_eclipse.html]. Но опять таки только для чтения. Это поможет вам ориентироваться в том, что я буду писать ниже.

Я предполагаю, что у читателя операционная система Линукс, и пути могут немного отличаться от тех, что буду давать я. Но опытный пользователь, я думаю, разберестя куда нужно бдует перйти.

Также я предполагаю, что у читателя уже установлены библиотеки OpenCV (лично я устанавливал через yumex).

Первое. Если вы еще не запустили Делаем новый проект: File -> New -> C++ Project.
Poject name: "firstopencv". Хотя вы можете выбрать другое. Но в рамках статьи рекомендую остановиться на этом.
Project type: Executable -> Empty Project;
Toolchain: Linux GCC. Жмем Finish.

Второе. На вкладке Project Explorer выбераем дирректорию firstopencv. Жмем правой кнопкой New -> Folder, называем ее "src".
На дирректории "src" правой нопкой мишы New -> Source File (C++);
File name: firstopencv.cpp

Третье. Ставим курсок на только что созданный файл. Идем Project -> Properties.
C\C++ Build -> Tools Settings -> GCC C++ Compiler
-> Command line pattern в конец строки добавляем следующу строку `pkg-config --cflags --libs opencv` . Обращаю ваше внимание на используемые ковычки. Они должны быить именно такими (находятся на русской букве Ё).
GCC C++ Linker Command line pattern добавляем следующу строку `pkg-config --cflags --libs opencv`

Четвертое. Учим Eclipse анализировать исходные коды. В том же Project Properties идем в Preprocessor Includes -> Providers. Убераем галку с CDT GCC Built-in Compiler Settings и устанавливаем на CDT GCC Built-in Compiler Settings MinGW.
Забыл сказать C\C++ Development Tools у вас уже должны быть установлены ;)
Жмем ОК.

Пятое. Проверка.
Для наглядности, я использовал этот текст программы

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/opencv.hpp>

#include <iostream>

int main(int argc, char** argv)
{
    cv::Mat image;
    image = cv::imread(argv[1], 1);

    if(argc != 2 || !image.data)
    {
        std::cout << "No image data \n";
        return -1;
    }

    cv::namedWindow("Display Image", CV_WINDOW_AUTOSIZE);
    cv::imshow("Display Image", image);

    cv::waitKey(0);

    return 0;
}

После компиляции, запустив приложение с путем к файлу с изображением в качестве первого параметра вы увидите изображение на экране.




2013-09-21

MonoDevelop автоматичекское форматирование исходного кода C#

    В данной статье я расскажу как настроить и использовать автоматическое форматирование исходного кода в IDE MonoDevelop для языка программирования C#.

    Я больше чем уверен, что читатель уже написал довольно много строк кода. Также уверен, что были случаи, когда приходилось вставлять части кода во вложенные структуры. И хорошо, если вложеность 2-3 уровня, и строк кода 3-4, тут клавишой Tab еще можно справиться. А вот что делать, если вложенность кода (условный оператор, например) большая да и строчек кода много. По умолчанию редкатор MonoDevelop вставит текст с таким же отступом, откуда он был скопирован. На счастье программиста MonoDevelop обладает функцие автоматического форматирования кода, нам остается только настроить "форматировщик" и научиться его вызывать.

    Итак, этап 1. Настройка форматирования кода.
    Запускаем MonoDevelop, если вы еще этого не сделали. Открываем пункт меню Tools -> Options. На левой панели разных настроек выбираем пункт Source Code\Code опцию Formatting C# source code и выбераем вкладку C# Format (справа) жмем кнопку Edit.
   В окне "Edit Profile" вы можете настроить форматирование блоков кода, как вам будет удобно. В левой части окна представлены виды конструкций, сгруппированные по категорями. Справа показан результат применения тех или иных параметров. "По играйтесь" с настройками. Я рекомендую вам настроить как требует стандарт Ecma-334.
    Настроив форматирование как нужно нажмите кнопку "ОК", для применения всех измнений.

    Этап 2. Автоматическое форматирование.
    Теперь переходим к настройке Preferences\Key Bindings в группе Edit находим пункт Format Document, выбираем его и внизу окна в поле "Edit Binding" жмем клавиши Ctrl + Alt + F. Жмем клавишу "ОК". Готово!
    Теперь нажав клавиатурное сочетание "Ctrl + Alt + F" ваш код будет крассиво отформатирован, так как вы его настроили в первом этапе.

    При желании воспользоваться форматированием кода с помощью мыши это можно выполнить выбрав пункт меню Edit -> Format -> Format Document.

2013-07-31

Цитаты о программировании и программистах

-- Один из принципов программирования: "больше кода = больше ошибок, меньше кода = меньше ошибок". Из книги Томас Кайтс, Oracle для профессионалов.

--Код всегда содержит ошибки. Одно из правил программирования

--Можно создать самолет с любыми техническими характеристиками, которые только пожелает Министерство военно-воздушных сил, если при этом не требуется, чтобы он мог летать. Вилли Мессершмидт (выдающийся немецкий авиаконструктор времен второй
мировой войны)

--"Совещания не родили ни одной великой мысли, но похоронили некоторое число идиотских....."    Фрэнсис Скотт Фицджеральд

--«Пишите код так, как будто сопровождать его будет склонный к насилию психопат, который знает, где вы живете». Стив Макконнелл.

--Мы слишком усложнили программное обеспечение и забыли главную цель. Джим и Сандра Сандфорс

--Технология — странная вещь. Одной рукой она дает вам великие дары, а другой — наносит удар в спину. С. П. Сноу (цитата из Jarman, 1992)

--Позвоните по вышеуказанному номеру и испытайте невероятное разочарование от нашей системы голосовой почты. Надпись под рекламным объявлением одной из марок обуви

--Нет ничего более невозможного, чем написать книгу, которая бы получила одобрение каждого читателя. Мигель де Сервантес

--Если индивидуальное взаимодействие с некоторой системой не проходит для пользователя легко и комфортно, то в результате этот недостаток негативным образом отражается на качестве работы всей системы, независимо от того, насколько она хороша в других своих проявлениях. Цитата из книги Раскин Д. Интерфейс. Новые направления в проектировании компьютерных систем

--Мое определение операционной системы звучит таким образом: "То, с чем приходится возиться перед тем, как начать возиться с программой.". Цитата из книги Раскин Д. Интерфейс. Новые направления в проектировании компьютерных систем

--Один человек, один компьютер. Слоган компании Apple Computer

--Хороший программист - это тот, кто смотрит в обе стороны переходя дорогу с односторонним движением. Даг Линдер

--Любой дурак может написать код, понятный компьютеру. Хороший программист пишет код понятный человеку. Мартин Фаулер

--Отличие кодера от разработчика. Кодеры пишут код, Разработчики создают продукт. Из одного из вебинаров по программированию.

--Если индивидуальное взаимодействие с некоторой системой не проходит для пользователя легко и комфортно, то в результате этот недостаток негативным образом отражается на качестве работы всей системы, независимо от того, насколько она хороша в других своих проявлениях. Раскин Джозефф

2012-08-20

GTK+: Первое оконное приложение в Linux


Цель: написать оконное приложение с использдованием библиотек GTK;
Операционная система: Fedora 17;
Язык программирования: С/С++;
Инструменты: Gedit, дебаггер gdb, кмпилятор gcc 4.7.0, termintal
Используемые источники дополнительной информации:
  1. http://www.gtk.org/documentation.php;
  2. Ален И. Голуб Правила программирование Си и Си++ 2001;
  3. http://developer.gnome.org/gtk-tutorial/stable/c39.html;
  4. www.unknownroad.com/rtfm/gdbtut/gdbuse.html;
   ... Начнем.
   Статья взята из [3]. Практически, она является переводм. Но здесь я использую свое толкование.
   Итак, нам необходимо написать оконное приложеное. На первый взгляд это может оказаться сложниым. Но в рузультате вы прийдете к выводу, что это даже проще, чем на Window, даже пользуясь удобными средствами разработки.
   Начну с теории. В трех словах. Простая программа с использованием GTK может быть легко написана в одном файле. Для создания оконного оприложения необходимо предворительно установтиь библиотеки (установка которых, в данной статье не обсуждается, автор предполагает, что на компьютере уже установленно все необходимое). Используя диррективу включения необходимо подключить библиотеку gtk.h. В ней находится все необходимое для создания базовых окон и элементов управления и работы с собитиями.
   Так же как и в консольном приложении (в принципе во всех программах С/С++), так и в окнном, точкой входа в программу является функция main(argc, argv[]).
   Наше приложение будет состоять из окна с одной кнопкой по середине. При нажатии на нее в консоль дебаггера будет выводитсья строка "Hello World!!!". Ну конечно! Именно эта строка, а вы как подумали? Это же первое приложение, а традиции нарушать нельзя.
      Одной из особенностей оконных приложений является то, что все действия выполняемые в программой начинаются после возникновения определенного события. Отследив событие тому или иному элементу управления, можно запрограммировать действия программы. При нажатие на кнопке будет отслеживаться собыитие "clicked". Для каждого события создается определенная функция, которая вызывается в результате того или иного события.
   После инициализации приложения, события отслеживатются специальной функцией gtk_main().
   Мы будем отслеживать два события: клик мыши на кнопке, и закрытие окна. Кстати при закрытии окна, на вывод дебаггера будет вызываться функция, которая будет выводить на экран с текстом - "delete event occurred".

   Так, основное я довел, а теперь практика.
   Подключаем библиотеку GTK:
#include <gtk/gtk.h>
Теперь опишем функцию, которая будет выполняться при возникновении событи нажатия мыши по кнопке на форме:
//--------------------------------------------------------------------------------
static void hello( GtkWidget *widget,
                   gpointer   data )
{
    g_print( "Hello World\n" );
}
На первый взгдя такой стиль описания функций может показаться странным, но он улучшает читабельность программы. К тому же можно написать коментарий к каждому аргументу функции. Функция g_print() выводит текст в консоль при работе дебаггера. Очевидно, что аргументом этой функции является выводимый текст.
   Правило 38. Используйте штриховую линию для зрительного разделения подпрограмм  из [2]. Штриховая линия помагает визуально отделить функции друг от друга, и улучшает читабельность программы.
    Также примечательно обратить внимание на правило 42. Выравнивайте скобки вертикально по левой границе [2]. На первый взгляд стиль Кэрнигана может показаться удобным, но это оказывается наоборот, когда размер текста программы увеличивается.

Продолжаем. Событие, закрытия окна:
//--------------------------------------------------------------------------------
static gboolean delete_event( GtkWidget *widget,
                              GdkEvent  *event,
                              gpointer   data )
{
    gtk_main_quit();
    g_print( "delete event occurred\n" );
    return FALSE;
}
Функция gtk_main_quit() выполняет выходи из приложения. После выполнения этого кода, на экран дбеггера выведется текст сообщения и приложение закончит свою работу.

Теперь пишем функцию входа в приложение:
//--------------------------------------------------------------------------------
int main( int  argc,
          char *argv[] )
{
}
Весь нижеприведнный код помещать внутри этой функци.
GtkWidget *window;  // windows object
GtkWidget *button;  // button on the canvas
Первая строка создает объект окна, вторая элемент управления кнопка.
Далее необходимо обработать аргументы запуска программы, если таковы были:
gtk_init( &argc, &argv );
Теперь выполняем код создания окна, непосредственно:
window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
После создания окна необходимо прописать все действия необходимых событий.
Вызов функции delete_event() при закрытии окна
g_signal_connect( window, "delete-event", G_CALLBACK( delete_event ), NULL );
Функция g_signal_connect() используется для обработки событий. Перывый аргумент указывает соыбтие какого элемента упрваления следует отлавливать. Второй аргумент указывает, какое событи необходимо обработать, в нашем случае это уничтожение окна. Третий - указывает на функцию, вызываемую при возникновении события. Четвертый - указатель на данные передваемые вызываемой функции. Вы наверняка заметили, что у hello() и delete_event() есть аргумент   gpointer data. Вот именно в этот аргумент передаются данные.
Может возникнуть вопрос, - "как это окно является элементом управления, ведь window - это окно?". Вообще говоря, все элемнты управления, кнопки, скроллбары, переключатели и т.д., в том числе и окна воспринимаются как окна. Так что, в принципе их можно рассматривать как одно и то же.
Теперь делаем границу 10 пикселей от краев окна:
gtk_container_set_border_width( GTK_CONTAINER( window ), 10 );
Создаем кнопку:
button = gtk_button_new_with_label( "Hello world" );

Как вы уже смогли понять, вышеуказання функция создает кнопку с меткой "Hello World".
Теперь опишем обработку сигнала нажатия кнопки:
g_signal_connect( button, "clicked", G_CALLBACK( callback ), NULL );
Далее, добавляем созданную кнопку на окно:
gtk_container_add( GTK_CONTAINER( window ), button );

Отображем кнопку и окно:
gtk_widget_show( button );
gtk_widget_show( window );
Затем вызываем функцию, отлавилвающую все события окна. По сути дела, функция gtk_main() и запускает работу приложения.
gtk_main();
Ну и на последок возвращаем ноль, при оконочании работы приложения:
return 0;
Сохраняем файл под именем "base.cpp". Теперь нам необходимо скомпелировать наше приложение с возможностью отладки. Делается это так:
    gcc -g base.cpp -o base `pkg-config --cflags --libs gtk+-2.0`

Есть два замечания. Первое, парамент -g нужно ставить перед именем исходно файла, в противном случае компилятор просто выдаст ошибку. Второе - ковычки нужно использовать именно такие, как показано в строке выше. Если использовать символ single quote, компиляции не будет.
   Теперь запускаем программу удобным для вас способом, и наслаждаемся своим произведением искусства.

2012-04-30

Ассемблер - регистры общего назначения


Цель: Изучить регистры общего назначения, а также научиться их использовать.
Используемые источники дополнительной информации:
   1.  http://www.codenet.ru/progr/asm/regs.php;

   Регистр - это определенный участок памяти внутри самого процессора, от 8-ми до 64-х бит длиной, который используется для промежуточного хранения информации, обрабатываемой процессором. Некоторые регистры содержат только определенную информацию.

   Общее описание регистров
EAX – Accumulator
   Применяется для хранения промежуточных данных. В некоторых командах использование этого регистра обязательно;
EBX – Base
   Применяется для хранения базового адреса некоторого объекта в памяти;
ECX – Counter
   Применяется в командах, производящих некоторые повторяющиеся действия. Его использование зачастую неявно и скрыто в алгоритме работы соответствующей команды.
   К примеру, команда организации цикла loop кроме передачи управления команде, находящейся по некоторому адресу, анализирует и уменьшает на единицу значение регистра ecx/cx;
EDX – Data
   Так же, как и регистр eax/ax/ah/al, он хранит промежуточные данные. В некоторых командах его использование обязательно; для некоторых команд это происходит неявно.
   На примере регситра EAX рассмотрим структуру регисттра. 8 бит регистра AX - AH и AL, т.е. H – верхний регистр, L – нижний регистр. Вместе они образуют регистр AX, и состоит из 16 бит. При переходе архитекуры процессоров на 32 бит к регистрам добавлена буква E, что означает extended (расширенный в переовде с английского).
   Графически структуру можно изобразить так:

2012-04-29

TASM: Перевод 16-ричного числа в двоичное

Цель: написать программу для перевода 16-ричного числа в символьном представлении в двоичное. Вывести результат на экран;
Инструменты: TASM 5, Turbo Debugger (из комплекта TASM), Notepad++ v.5.9
Используемые источники дополнительной информации:
   1. Юров В.И. Справочная система по языку ассемблера IBM PC к книге Assembler: учебный курс издательство «Питер» 1998 год (ссылка для скачивания руководства в chm формате);
   2. Таблица асхи кодов;
   3. Зубков С.В.  - Assembler для DOS, Window и Unix- 2000;
   4. Обсуждение на тему: вывод числа в двоичном виде на форуме cyberforum.ru;
ОС: Windows XP SP3

   Для начала небольшое Intro. В данной статье, как пользоваться той или иной командой я описывать не буду. Этим я займусь в других статьях, по тематике более подробно. И по мере написания новых статей, в этой я буду размещать ссылки, на изучение того, или иного материала. Для отладки программы я использую дебаггер поставляемый вместе с компилятором. Находится он в каталоге \tasm\bin, приложение td.exe. Это дебаггер для 16 разрядных программ. С его помощью можно просматривать построчное выполнение программы. Клавишей F8 выполняется переход по инструкциям. Клавишей F7 можно пермещаться по инструкциям внути процедур и циклов.
   А теперь перейдем к делу.
   Ввод: с клавиатуры вводится шестнадцатиричное число из двух цифр, используюя функцию DOS - 07h, int 21h. Вывод: результат преобразования выводится на экран, используюя функцию DOS - int 29h (выводит символ из al)
   Любой символ, вводимый с клавиатуры записывается в регистр не как сам символ, а в виде ASCII кода в 16-ричном виде. Т.е. если мы введем с клавиатуры к примеру число 5, то в регистр будет занесено значение 035. Таблица ASCII-кодов представлена в заголовке статьи.
   Функция DOS 07h — Считать символ из STDIN без эха, с ожиданием и без проверки на Ctrl-Break Ввод: АН = 07h, Вывод: AL = код символа.
   Как я уже говорил раньше, все вводимые с экрана символы записываются в регистры в виде ASCII кода.
   Функция DOS 02h — Записать символ в STDOUT с проверкой на Ctrl-Break
Ввод: АН = 02h, DL = ASCII-код символа. Вывод: Никакого, согласно документации, но на самом деле: AL = код последнего записанного символа (равен DL, кроме случая, когда DL = 09h (табуляция), тогда в AL возвращается 20h).
   Начнем с самого простого. Напишем каркас приложения.

.model small
.stack 100h
.data
.code
start:
 
end start

   Эта программа ничего не делает. Но именно сюда мы будем дописывать нужные нам фрагменты.
   .model small директива объявления модели памяти. Код размещается в одном сегменте, а данные и стек в другом.
   .stack 100h объявляет сегмент стека размером в 256 байт
   .data директива сегмента данных. После нее мы будем объявлять переменные.
   .code директива сегмента кода. Следом за этой директивой размещается код программы.
   Код программы помещается между строками "start:" и "end start"
   В многих программах часто необходимо выполнять перевод каретки на новую строку. По этому я сразу решил написать для этого макрос. Макрос будет выполнять вывод переменной, в которой содержатся коды первода каретки. Переменная определяется следующим образом (помним, что объявление переменных выполняется после директивы .data):

nline db 10, 13, '$'

Один из вариантнов размещения макросов и процедур внутри кода, это вначале программы. Я использую этот способ. Код макроса:

newline macro
  lea dx, nline
  mov ah, 9
  int 21h
endm

   Хочу сделать одно замечание по использованию команы lea. Ее эквивалентом является команда mov <операнд>, offset <операнд>. При использовании lea не возникает проблем с выводм строк на экран.
   Теперь, вызывая "newline" в программе, курсор будет переводиться на начало новой строки. Сейчас этот макрос может быть бесполезен. Потому как его я использую только несколько раз. Но в будующем, в других программах он может пригодиться.
   Такой подход написания макроса для перевода курсона на начало новой строки довольно не плох. Но зависит от переменной, которая находится вне тела макроса. По этому целесообразней использовать такой набор команд, что макрос будет независимый. И решение есть. Следующий макрос немного длинней, но его использование уже гибче.

newline macro
    mov ah, 02h        
    mov dl, 10        
    int 21h
    mov dl, 13        
    int 21h
endm

   Именно его мы и будеи использовать в нашей программе.
   Теперь рассмотрим процедуру, выполняющую первод ASCII-кода символа введенного с экрана в цифру, и помещает его в регистр al. В случае, если символ не входит в дипозон тех, которыми можно представить 16-ричное число, процедура выполняет выход из программы.

check proc
cmp al,'f' ; вместо f будет подставлен ASCII код: 066h
ja errcatch ; если код больше 066h то перейти к концу процедуры
cmp al,'a' ; вместо a будет подставлен ASCII код: 061h
jae isschar ; если код больше либо равно 061h то символ
; выполняем переход на метку перевода кода в число

cmp al, 'F'          
ja  errcatch          
cmp al, 'A'          
jae isuchar


cmp al, '9'
ja  errcatch
cmp al, '0'
jae isnum

isnum: ; вычитание числа из кода символа,
sub al, 30h ; для представления числа в программе, как число
jmp ok
isschar:
sub al, 57h
jmp ok
isuchar:
sub al, 37h
jmp ok


errcatch: ; аварийное прекращение программы
newline ; новая строка
lea dx, crash ; сообщение об ошибке
mov ah, 9
int 21h
jmp exit ; перейти к метке окончания программы
ok: ; процедура выполнена успешно
ret
check endp

   Команда cmp предназанчена для сравнения двух оперндов. Следующая за ней команда выполняет переход в зависимости от результата сравнения. В нашем случае ja - Jump if above. Т.е. перейти к метке, если значение больше. Переход выполняется на метку выводящую на экран сообщение об ошибке, и выполняется выход из программы.
   Первую часть процедуры можно трактовать так: перейти по метке isschar (т.е. введенное число - маленькие буквы), если символ в диапазоне от a до f. Два последующих сравнения аналогичны первому. Я думаю разъяснянию не подляжат.
   Для преобразования кода символа непосредственно в число, нужно от него отнять опрееделенную цифру. Какие именно числа нужно отнимать предствалено ниже:
   Для цифр 0-9 отнимать 30h
   Для цифр A-F отнимать 37h
   Для цифр a-f отнимать 57h
   Этими вычитаниями как раз и занимается следующая часть кода процедуры, в зависимости от результата сравнения. Так что после ее успешного выполнения в регистр al помещается 16-риченое число. И теперь с ним можно работать.
   Теперь осталось совмес немного - получить от пользователя символы, и перевести их в другу систему счисления.
   Для того, чтобы пользователь знал, что мы от него хотим, выведем для него на экран текст, с просьбой ввести символы. В разделе .data объявляем переменную со строкой приглашения: intro db 'Enter number: $'. Также следует заметить, что символ доллара (он же символ окончания строки) в конце строки важен. Если его не указать, то тогда вместе с нашим сообщением на экран выведется мусор, который находится за пределами переменной. А нам этого не нужно!
   Для вывода сообщения необходимо в регистр сегмента данных сегмент данных. Выполняется это следующими двумя командами:

mov ax, @data ; сегментный адрес
mov ds, ax     ; помещается в DS


  Сразу возникает вопрос, - "А почему бы сразу не выполнить команду mov ds, @data". А вот нет. В сегментный регситр смещение можно поместить только из другого регистра.
   Вывод приветствия выполняется следующим образом:

mov dx, offset intro
mov ah, 9
int 21h  

   Первая строка выполняет помещение смещения перемнной intro в регистр dx. Втроая помещает функцию вывода строки из dx на экрна. 21h выполняет прерывание, в результате которого будет выведена строка на экран. Следует заменить, что функция 07h, к примеру, не выполнится, пока не выполнить прерывание (в нашем случае 21h).
   В этой программе введенные символы мы будем хранить в массиве. В разделе данных объявляем слудующим образом:
num db 2 dup(?)
   Так... Приветствие вывели, теперь нужно прочесть введенный символ. А делать мы это будем следующим образом:

mov ah, 7 ; считать символ в al
int 21h ; выполнение прерывания
call check ; проверка правильности ввода
mov num, al ; помещаем введенный символ в num

   Т.е. в регистр ah помещаем функцию считывания символа с экрана. Выполнив прерывание введнный символ помещается в регистр al. Затем выполняем процедуру check, которая переводит код симола в число. Ну и на последок, сохраняем переменную в массив.
   После ввода двух чисел, и помещения их в массив нужно произвести их конвертирование в двоичное число. Помещая первый введнный символ в bh, и втрой в bl получается неприятная вещ. Оба регистра выглядят как два нуля (00). После помещение числа в первый регистр, получаем, к примеру, 0e, после второго 04 (если это число 4). И общий вид регистра dx получается 0e04. А это не введнное число e4, а число e04. А для того, чтобы перевести число в двоичное, нам понадобится выполнять побитовый сдвиг регистра, и на выходе мы получим совсем, что нам нужно. Возникает вопрос,  - "Как поместить число в регистр в необходимом виде?".
   И этому есть решение! И даже два.
   Первое. Побитовый сдвиг регистра dl влево на 4, затем побитовый сдвиг регистра dx вправо на 4. Псле чего все число помещается в dl в виде e4. Выполняется это слудющим образом:

shl bl, 4 ; смещение содержимого bl на 4 бита влево
; это дает возможность разместить число в регистре рядом
; с первым введнным числом
shr bx, 4 ; смещение всего содержимого регистр bx

   Второе. Умножить регистр dl на 16(или на 010 в шеснадцатиричном виде). И прибавить к нему значение регистра dh. И результат будет аналогичен. Делается это так:


    mov al, 010h
    mul bl
    mov bl, al
    add bl, bh

   Какой выбрать, ришть вам. В этой статье я оставлю первый способ.
   Как я говорил выше, что-бы число сделать двичным, его нужно побитово сдвинуть. Так вот, его нужно не просто сдвигать, а сдвигать через флаг переноса. И каждый раз, после сдвига выполняя вывод символа 30h (а это символ 0) + значение флага переноса на выходе получится двоичное число. Посмотрим код:

mov cx, 8     ; количество итераций сдвига
cnv:     ; метка выполнение первода числа
    shl bl, 1  ; сдвиг регистра bl влево через флаг переноса
    mov al,'0' ; помещение ASCII-кода цифры 0 в регистр dl
    adc al, 0 ; прибавление к ASCII-коду нуля с учетом флага переноса
    int 29h ; выполнение прерывания: вывод символа из al
    loop cnv ; продолжение цикла - переход по метке

   Регистр cx отвечает за счетчик команд. По этому в него мы помещаем число итераций для следующего цикла - 8. Почему 8? А очень просто. Как выглядит число "e" в двоичной системе?  1110, а 4 - 0100, а 15? 1111. Т.е. для каждого введенного ичсла нам нужно по 4 символа в двоичном, вот и получаем 8 итераций (или 8 сдвигов в цикле).
   shl bl, 1 выполняет сдвиг содержимого регистра bl в лево на 1 бит. Левый бит помещается во флаг переноса (cf). В al помещает ASCII-код символа 0, Команда adc прибавляет к коду в al 0 или 1 в зависимости от состояния фалага cf. Ну а int 29h выполняет непосредственно вывод символа из регистра al.
   Фух! Сколько мы проделали много работы. Пора бы уже увидеть результат наших трудов. А результат представлен ниже. Это конечный код программы.

.model small           ; модель памяти, используемая для ЕХЕ
.stack 100h            ; сегмент стека размером в 256 байт
.data
  intro db 'Enter number: $' ; сообщение приветствия
  num db 2 dup(?) ; массив с двумя числами
  crash  db 10, 13, 'Input error $' ; сообщение об ошибке
.code


; макрос перехода на новую строку
newline macro
    mov ah, 02h  ; функция вывода символа из регистра dl на экран
    mov dl, 10   ; перевод каретки на новую строку
    int 21h
    mov dl, 13   ; перенос курсора на начало строки
    int 21h
endm


; процедура проверяет, является ли символ в регистре al принадлжеащим
; диапазону букв и цифр, пренадлежащих 16-ричному представлению чисел
; и переводит ASCII код в цифру
check proc
cmp al,'f' ; вместо f будет подставлен ASCII код: 066h
ja errcatch ; если код больше 066h то перейти к концу процедуры
cmp al,'a' ; вместо a будет подставлен ASCII код: 061h
jae isschar ; если код больше либо равно 061h то символ
; выполняем переход к метке перевода кода в число
cmp al, 'F'            
ja  errcatch          
cmp al, 'A'            
jae isuchar


cmp al, '9'
ja  errcatch
cmp al, '0'
jae isnum

isnum: ; вычитание числа из кода символа,
sub al, 30h ; для представления числа в программе, как число
jmp ok
isschar:
sub al, 57h
jmp ok
isuchar:
sub al, 37h
jmp ok

errcatch: ; аварийное прекращение программы
newline ; новая строка
lea dx, crash ; сообщение об ошибке
mov ah, 9
int 21h
jmp exit ; перейти к метке окончания программы
ok: ; процедура выполнена успешно
ret
check endp


start:
mov ax, @data ; сегментный адрес
mov ds, ax     ; помещается в DS

    mov dx, offset intro ; попещение приветствия в область данных
    mov ah, 9
    int 21h     ; функция DOS "вывод строки"

mov ah, 7 ; считать символ в al
int 21h ; выполнение прерывания
call check ; проверка правильности ввода
mov num, al ; помещаем введенный символ в num


mov ah, 7 ; считать символ в al
int 21h ; выполнение прерывания
call check ; проверка правильности ввода
mov num+2, al ; помещаем введенный символ в 
                 ; num+2 (второй элемент массива)
newline ; перходим на новую строку
mov bh, num ; Помещение первого числа в bh
mov bl, num+2 ; помещение второго числа в bl
shl bl, 4 ; смещение содержимого bl на 4 бита влево
; это дает возможность разместить 
                 ; число в регистре рядом
; с первым введнным числом
shr bx, 4 ; смещение всего содержимого регистр bx
; после чего, число будет полность в регистре bl
    mov cx, 8 ; количество итераций сдвига
cnv:     ; метка выполнение первода числа
shl bl, 1 ; сдвиг содержимого регистра bl влево через флаг переноса
    mov al,'0' ; помещение ASCII-кода цифры 0 в регистр dl
    adc al, 0 ; прибавление к ASCII-коду нуля с учетом флага переноса 
    int 29h ; выполнение прерывания: вывод символа из al
    loop cnv ; продолжение цикла - переход по метке

newline       ; перводим курсор на новую строку

mov ah, 1 ; Ожидание нажатия клавиши пользователем
int 21h


exit:
    mov ax, 4C00h ; аналог: mov ah, 4ch
    int 21h       ; функция DOS "завершить программу"
end start

   Outro. Буду благодарен за ваши коментарии и найденные ошибки! Надеюсь эта статья поможет понять вам необходимые основы программирования на языке ассемблера. Успехов в обучении вам!!!