Компьютерный форум
Правила
Вернуться   Компьютерный форум > Форум программистов > Языки программирования > Assembler
Перезагрузить страницу Начинаю борьбу за "кодеризацию" населения
Ответ
 
Опции темы Опции просмотра
  (#16 (permalink)) Старый
TNT TNT вне форума
Member
 
Сообщений: 509
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
Регистрация: 29.03.2003
По умолчанию 09.05.2003, 19:59

Вот прочитал книгу "Pentium 4" (та что от издания Питер Пресс)... очень хорошая книга, которая и рассказывает о всех этих новых технологиях итд. Четко узнал о работе конвейеров, стеке, MXX , SIMD ... Так вот, если нужно знать что и как обрабатывается - читайте её.
Я аот например знаю основы программирования на АСМе, но в подробности не вникаюсь. Теперь в башке у меня так скажем "всё на своих полочках" и я представляю, что и как обрабатываеться. Считаю ,что иногда без АСМ действительно не обойтись, но лично я его использую крайне редко. Да... любой программер должен иметь хоть БАЗОВЫЕ навыки АСМ, но ведь не обязательно вникать в подробности.
Вот вы пишите, мол секретарши. А сейчас таких секретарш больше требуется, чем всех других. Да, VB - супер-высокоуровневый язык, но ведь и у него есть своя ниша! НЕ всегда есть время написать простенькую прогу, а на VB - это сделаешь за 5 минут. И ещё: в качестве обучающего языка VB подходит отлично!!!
Ответить с цитированием
  (#17 (permalink)) Старый
S.Yu.Gubanov S.Yu.Gubanov вне форума
Member
 
Сообщений: 587
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
Регистрация: 03.12.2002
По умолчанию 30.05.2003, 18:46

Цитата:
Originally posted by AssAsin
[b]... Спрашивается, на кой черт ассемблер человеку, который пишет в Delphi? ...
Я чуть с кресла не упал...
В самом деле и на кой черт мне понадобилось писать ассемблерную вставку использующую SSE команды Pentium 3? Ну ладно позволила она одновременно обрабатывать не одно число, а четыре (т.е. увеличила скорость работы программы в четыре раза). Ну подумаешь... А вот зачем мне понадобилось заменять восемь инструкции
{1/x0, 1/x1, 1/x2, 1/x3} and {sqrt(x0), sqrt(x1), sqrt(x2), sqrt(x3)}
на четыре {1/sqrt(x0), 1/sqrt(x1), 1/sqrt(x2), 1/sqrt(x3)} тоже непонятно, ну подумаешь увеличил скорость еще в два раза (итого в восемь)... Восемь раз - это же ерунда, зачем это Delphi ?

Хотя нет, зря я проявил такой сарказм, ведь ты наверняка имел в виду ассемблер обычный 0x86 а не MMX, SSE, SSE2 и тому подобные примочки. Тогда действительно Delphi программисту не надо знать обычный ассемблер, просто потому что и так "Delphi Language и ASM - близнецы братья". Вот доказательство:
Возьми Delphi 7 скомпилируй следующую типичную дельфийскую процедурку
Код:
procedure BSort(const a: TArrayOfCardinal);
// Сортирует массив a[] неотрицательный целых чисел cardinal
// методом поразарядной (побайтовой) сортировки за 5 проходов.
// Нулевой проход - сбор данных для создания индексов,
// первый-четвертый проходы - сортировка по 0-3 байтам.
// Использует вспомогательный массив buff[] такого же размера,
// что и a[].
// Время сортировки 10'000'000 целых чисел равно 1.31 сек
// включая 0.094 сек на создание буффера buff[].
// на Pentium 4 1800Mh 512Kb 256Mb DDR266, Windows 2000 SP2
// Автор: Сергей Ю. Губанов, S.Yu.Gubanov@inbox.ru, 2003 г.
var
  buff: TArrayOfCardinal;
  index0, index1, index2, index3: array[0..255] of cardinal;
  h: integer;

    procedure LoadIndexies;
    // Процедура LoadIndexies Вычисляет индексы
    // j = index0[m] -- позиция в массиве a[j], в которую
    // надо вставить число, нулевой байт которого равен m.
    // ...
    // j = index3[m] -- позиция в массиве a[j], в которую
    // надо вставить число, третий байт которого равен m.
    var p, p_stop: ^byte;
        i: integer;
    begin
      FillChar(index0, SizeOf(index0), 0);
      FillChar(index1, SizeOf(index1), 0);
      FillChar(index2, SizeOf(index2), 0);
      FillChar(index3, SizeOf(index3), 0);
      p_stop := @a[h];
      inc(p_stop, 4);
      p := @a[0];
      repeat
        inc(index0[p^]);
        inc(p);
        inc(index1[p^]);
        inc(p);
        inc(index2[p^]);
        inc(p);
        inc(index3[p^]);
        inc(p);
      until p = p_stop;
      for i:=1 to 255 do
        begin
          inc(index0[i], index0[i-1]);
          inc(index1[i], index1[i-1]);
          inc(index2[i], index2[i-1]);
          inc(index3[i], index3[i-1]);
        end;
      for i:=255 downto 1 do
        begin
          index0[i] := index0[i-1];
          index1[i] := index1[i-1];
          index2[i] := index2[i-1];
          index3[i] := index3[i-1];
        end;
      index0[0] := 0;
      index1[0] := 0;
      index2[0] := 0;
      index3[0] := 0;
    end;

var  p: ^byte;
     g, q, q_stop: ^Integer;
begin
  h := High(a);
  if h >= 0 then
  begin
    SetLength(buff, h+1);
    LoadIndexies;
    begin{SORTING}
      //Первый проход сортировки
      // - по нулевому байту
      q_stop := @a[h];
      inc(q_stop);
      q := @a[0];
      p := @a[0];
      g := @index0[p^];
      repeat
        buff[g^] := q^;
        inc(g^);
        inc(p, 4);
        g := @index0[p^];
        inc(q);
      until q = q_stop;
      //Второй проход сортировки
      // - по первому байту
      q_stop := @buff[h];
      inc(q_stop);
      q := @buff[0];
      p := @buff[0];
      inc(p);
      g := @index1[p^];
      repeat
        a[g^] := q^;
        inc(g^);
        inc(p, 4);
        g := @index1[p^];
        inc(q);
      until q = q_stop;
      //Третий проход сортировки
      // - по второму байту
      q_stop := @a[h];
      inc(q_stop);
      q := @a[0];
      p := @a[0];
      inc(p, 2);
      g := @index2[p^];
      repeat
        buff[g^] := q^;
        inc(g^);
        inc(p, 4);
        g := @index2[p^];
        inc(q);
      until q = q_stop;
      //Четвертый проход сортировки
      // - по третьему байту
      q_stop := @buff[h];
      inc(q_stop);
      q := @buff[0];
      p := @buff[0];
      inc(p,3);
      g := @index3[p^];
      repeat
        a[g^] := q^;
        inc(g^);
        inc(p,4);
        g := @index3[p^];
        inc(q);
      until q = q_stop;
    end;{SORTING}
  end;
end;
поставь где-нибудь в ней точку останова, запусти, а потом нажми Debug -> view CPU, чтобы позыркать получившийся ассемблерный код. И что же ты увидишь? Да практически все будет переведено в asm один к одному, это означает то что грамотное написание программы на Delphi Language сравнимо с написанием программы на ASM, а следовательно использовать обычный ASM Дельфинистам в самом деле не очень-то уж и надо...

P.S.
Да, вобщем-то, я просто пошутил...
Ответить с цитированием
  (#18 (permalink)) Старый
VictN VictN вне форума
Новичок
 
Сообщений: 8
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
Регистрация: 11.06.2003
По умолчанию 12.06.2003, 11:36

Я считаю, что не всем нужно знать ассемблер, хотя начинал я с ассемблера. Прикладникам он ни во что не упирается, ну не хватит им мозгов, чтобы выучить его, да и не нужен им. Другое дело системщики, крякеры или те, кто хочет понять работу работу программы и ОС, то им надо, да они это и сами все понимают. Так что, не фиг население насильно тянуть в асм. Кто хочет и кому надо сам придет.
Ответить с цитированием
  (#19 (permalink)) Старый
Anonymous
Guest
 
Сообщений: n/a
По умолчанию Если подумать... - 17.06.2003, 18:01

Цитата:
Originally posted by S.Yu.Gubanov
[b]Да практически все будет переведено в asm один к одному, это означает то что грамотное написание программы на Delphi Language сравнимо с написанием программы на ASM, а следовательно использовать обычный ASM Дельфинистам в самом деле не очень-то уж и надо...
P.S.
Да, вобщем-то, я просто пошутил...
Можно/нужно разграничить предмет разговора. Если понимать под программой совокупность следующих частей:
а) набор алгоритмов;
б) связи между алгоритмами;
в) структуры данных,
то можно сравнить использование ассемблера и ЯВУ в каждой из этих частей.

А.
Для реализации алгоритмов ассемблер более удобен в силу своей большей гибкости. Совсем не случайно Кнут в своей известной книге "Искусство программирования" приводит алгоритмы в записи на ассемблере (MIX). Приведу простой пример. Во многих алгоритмах БПФ (быстрое преобразовании Фурье) используется переупорядочивание массива. Элементы массива меняются местами по следующему правилу. Для индекса каждого элемента вычисляется "зеркальный" индекс и, если "зеркальный" индекс больше, то элементы массива меняются местами. (У зеркального" индекса биты следуют в обратном порядке: младший бит становится старшим, например, индекс 0100 имеет "зеркало" 0010). Попробуйте написать алгоритм зеркалирования на ЯВУ и ассемблере, сравните их по наглядности и эффективности. И отметьте закономерность: чем более эффективна запись алгоритма на ЯВУ, тем сложнее она для понимания и, наоборот, чем более понятна запись алгоритма, тем менее эффективен сам алгоритм. Но добиться того, чтобы самая эффективная реализация алгоритма на ЯВУ стала сравнимой с ассемблером, вряд ли удастся. При этом запись алгоритма на ассемблере легко воспринимается.

Б.
Связи между алгоритмами также эффективнее реализовать на ассемблере. Простой пример. В Windows "оконная" процедура начинается с поиска соответствующего обработчика сообщений. На ЯВУ поиск обычно компилируется в последовательность команд:
Код:
        cmp     [msg],WM_XXX
        je      XXX
        cmp     [msg],WM_YYY
        je      YYY
        cmp     [msg],WM_ZZZ
        je      ZZZ
        ...
Понятно, что при большом количестве обрабатываемых событий, такое представление алгоритма очень неэффективно. На ассемблере задачу можно решить значительно красивее и эффективнее. Например, все обрабатываемые сообщения складываются в один массив, а соответствующие им обработчики, в том же порядке, заносятся во второй массив. При поступлении сообщения сканируется первый массив, если сообщение найдено, то по тому же индексу из второго массива вызывается обработчик данного сообщения, в противном случае вызывается обработка по умолчанию. Теперь остается написать макроопределение на макроязыке ассемблера и пользоваться им. Наглядно, эффективно и очень удобно.
Рассматривая связи между алгоритмами, можно отметить то, что в ЯВУ относительно недавно стали применяться косвенные вызова подпрограмм, и применяются они, в основном, в ОО-расширениях при вызове методов объектов посредством VT (VMT). Крайне редко можно встретить использование косвенных вызовов в программах на ЯВУ. В то же время в ассемблере косвенные вызова являются одним из простых и эффективных способов виртуализации связей между подпрограммами, который применяется с давних пор. Перефразируя известное выражение, можно сказать, что "связи между подпрограммами на ЯВУ, можно сделать так, как допускает язык, а связи между подпрограммами на ассемблере можно сделать так, как требуется".

С.
По структурам данных нет принципиальных отличий между ассемблером и ЯВУ. Все структуры, существующие в ЯВУ, поддерживаются и современными ассемблерами (включая структуры данных объектов).
Ответить с цитированием
  (#20 (permalink)) Старый
S.Yu.Gubanov S.Yu.Gubanov вне форума
Member
 
Сообщений: 587
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
Регистрация: 03.12.2002
По умолчанию Re: Если подумать... - 17.06.2003, 18:37

Цитата:
Originally posted by ASU+-->
Цитата:
А. ...Попробуйте написать алгоритм зеркалирования на ЯВУ и ассемблере...
Согласен на 100%

<!--QuoteBegin-ASU

[b]Б. ...При поступлении сообщения сканируется первый массив...
Согласен на 100%. Как я понял, основная проблема тут в том чтобы быстро найти элемент в массиве. Для этого в (интеловском) АСМ-е есть, например,
Код:
REP SCAS
в то время как в ЯВУ от цикла никуда не денешься. Так?
Ответить с цитированием
Ads.
  (#21 (permalink)) Старый
Anonymous
Guest
 
Сообщений: n/a
По умолчанию Re: Если подумать... - 18.06.2003, 11:35

Цитата:
Originally posted by S.Yu.Gubanov
[b]Согласен на 100%. Как я понял, основная проблема тут в том чтобы быстро найти элемент в массиве. Для этого в (интеловском) АСМ-е есть, например,
Код:
REP SCAS
в то время как в ЯВУ от цикла никуда не денешься. Так?
И снова вопрос можно разделить на несколько составляющих:
а) эффективность кода, обеспечивающего переход к обработчику события;
б) компактность кода;
в) читабельность и понимаемость кода.
Что в этом свете могут предложить ЯВУ? По пп. А, Б - положиться на оптимизатор. По п. В - громоздкую и неудобную конструкцию, которую трудно охватить взглядом.
А что можно сделать на ассемблере? Прежде всего можно рассмотреть несколько алгоритмов поиска(!) и организации данных(!). Разнообразие алгоритмов и структур связано с количеством обрабатываемых сообщений. Если сообщений мало (примерно до пяти), то можно использовать тривиальную конструкцию, аналогичную описанной ранее:
Код:
                mov     eax,[@@msg]
                cmp     eax,WM_XXX
                je      @@WM_XXX
                cmp     eax,WM_YYY
                je      @@WM_YYY
                cmp     eax,WM_ZZZ
                je      @@WM_ZZZ
При большем числе сообщений (до десятка) такая конструкция становится неудобной для восприятия (загромождение полезного кода) и затратной для исполнения. В этом случае можно заменить ее на следующую:
Код:
DataSeg
@@Messages      dd  WM_XXX, @@WM_XXX
                dd  WM_YYY, @@WM_YYY
                dd  WM_ZZZ, @@WM_ZZZ
            ...
@@Num_Messages  = (($ - @@Messages) shr 3) - 1

CodeSeg
                mov     eax,[@@msg]
                mov     ecx,@@Num_Messages

@@1:            cmp     eax,[dword @@Messages + ecx * 8]
                je      [dword @@Messages + 4 + ecx * 8]
                loop    @@1
Можно отметить, что размер этого кода не зависит от количества обрабатываемых сообщений и при этом сам код достаточно компактен. Но с большим количеством сообщений он будет работать не эффективно. Поэтому можно рассмотреть еще один алгоритм, который сохранит достоинства данного алгоритма, но при этом будет эффективно работать с произвольно большим количеством сообщений:
Код:
CodeSeg
@@Messages      dd      WM_XXX, WM_YYY, WM_ZZZ, ...
@@Num_Messages  = ($ - @@Messages) shr 2
@@Hdl_Messages  dd      @@WM_XXX, @@WM_YYY, @@WM_ZZZ, ...

DataSeg
                mov     eax,[@@msg]
                mov     ecx,@@Num_Messages
                mov     edi,offset @@Messges
                cld
                repne   scasd
                sub     edi,offset @@Messages
                jmp     [dword edi + @@Hdl_Messages - 4]
Для больших списков сообщений этот алгоритм будет наиболее эффективен.

Сейчас необходимо сделать важное замечание. Прописывать каждый раз представленные базовые конструкции, да, еще и заменять одну другой (в случае, когда в процессе работы над программой потребовалось добавить обработку дополнительных сообщений) очень трудоемко, и в процессе внесения изменений легко допустить ошибку. Поэтому было бы желательно автоматизировать работу по написанию кода перехода к обработчику сообщений. Можно отметить, что представленные базовые варианты не зависят ни от сообщений, ни от адресов обработчиков. Следовательно, можно написать макроопределения, которые бы автоматически выполняли следующую работу:
а) подбирали нужный алгоритм, исходя из количества обрабатываемых сообщений;
б) автоматически создавали необходимые структуры данных и код;
в) делали код программы более простым и наглядным.
Можно рассмотреть достижимость поставленных целей, если это интересно, конечно.
Ответить с цитированием
  (#22 (permalink)) Старый
Влад Влад вне форума
Специалист
 
Сообщений: 3,884
Сказал(а) спасибо: 1
Поблагодарили 25 раз(а) в 25 сообщениях
Регистрация: 27.06.2002
Адрес: Санкт-Петербург
По умолчанию 18.06.2003, 13:29

Цитата:
Originally posted by Гость
[b]В Windows "оконная" процедура начинается с поиска соответствующего обработчика сообщений. На ЯВУ поиск обычно компилируется в последовательность команд:
cmp [msg],WM_XXX
je XXX
cmp [msg],WM_YYY
je YYY
cmp [msg],WM_ZZZ
je ZZZ
Это не совсем так. Если селекторы WM_... идут последовательно (а для большинства сообщений Windows это так, да и для пользовательских идентификаторов это правило соблюдается в большинстве случаев), то хитрые современные компиляторы генерируют таблицу переходов, и выбирают адрес перехода по таблице. Вот типичный код:
Код:
CODE:00413524                 and     eax, 7Fh
CODE:00413527                 cmp     eax, 13h       ; switch 20 cases
CODE:0041352A                 ja      loc_413647     ; default
CODE:00413530                 jmp     ds:off_413537[eax*4]; switch jump
CODE:00413530; ---------------------------------------------------------------------------
CODE:00413537 off_413537      dd offset loc_413647   ; DATA XREF: sub_413500+30r
CODE:00413537                 dd offset loc_41358C   ; jump table for switch statement
CODE:00413537                 dd offset loc_413598
CODE:00413537                 dd offset loc_4135A9
CODE:00413537                 dd offset loc_4135BA
CODE:00413537                 dd offset loc_4135C8
CODE:00413537                 dd offset loc_4135D6
CODE:00413537                 dd offset loc_4135D6
CODE:00413537                 dd offset loc_413647
CODE:00413537                 dd offset loc_413647
CODE:00413537                 dd offset loc_4135E3
CODE:00413537                 dd offset loc_4135EC
CODE:00413537                 dd offset loc_4135F6
CODE:00413537                 dd offset loc_413647
CODE:00413537                 dd offset loc_4135FF
CODE:00413537                 dd offset loc_413608
CODE:00413537                 dd offset loc_413616
CODE:00413537                 dd offset loc_413624
CODE:00413537                 dd offset loc_413632
CODE:00413537                 dd offset loc_41363B
CODE:00413587; ---------------------------------------------------------------------------
CODE:00413587                 jmp     loc_413647     ; default
CODE:0041358C; ---------------------------------------------------------------------------
Ответить с цитированием
  (#23 (permalink)) Старый
Anonymous
Guest
 
Сообщений: n/a
По умолчанию 18.06.2003, 15:11

Цитата:
Originally posted by Влад
[b]Если селекторы WM_... идут последовательно (а для большинства сообщений Windows это так, да и для пользовательских идентификаторов это правило соблюдается в большинстве случаев), то хитрые современные компиляторы генерируют таблицу переходов, и выбирают адрес перехода по таблице
Если посмотреть на наиболее часто обрабатываемые сообщения, то... никакой последовательности нет. Достаточно взглянуть на коды сообщений (числа приведены в шестнадцатиричной нотации):
Код:
WM_NULL                         = 0000
WM_CREATE                       = 0001
WM_DESTROY                      = 0002
WM_MOVE                         = 0003
WM_SIZE                         = 0005
WM_ACTIVATE                     = 0006
WM_SETFOCUS                     = 0007
WM_KILLFOCUS                    = 0008
WM_ENABLE                       = 000A
WM_SETREDRAW                    = 000Bh
WM_SETTEXT                      = 000C
WM_GETTEXT                      = 000Dh
WM_GETTEXTLENGTH                = 000E
WM_PAINT                        = 000F
WM_CLOSE                        = 0010
WM_QUERYENDSESSION              = 0011
WM_QUIT                         = 0012
WM_QUERYOPEN                    = 0013
WM_ERASEBKGND                   = 0014
WM_SYSCOLORCHANGE               = 0015
WM_ENDSESSION                   = 0016
WM_SHOWWINDOW                   = 0018
WM_WININICHANGE                 = 001A
...
WM_SETCURSOR                    = 0020
...
WM_NOTIFY                       = 004E
...
WM_KEYDOWN                      = 0100
...
WM_INITDIALOG                   = 0110
WM_COMMAND                      = 0111
WM_SYSCOMMAND                   = 0112
WM_TIMER                        = 0113
...
WM_PRINT                        = 0317
...
Сообщения, которые пропущены обрабатываются редко, как впрочем и WM_ERASEBKGND, WM_SYSCOLORCHANGE, а вот сообщения WM_COMMAND, WM_NOTIFY и т.п. вызываются почти в любой программе. Поэтому можно построить либо очень большой массив, либо выполнять поиск. Ситуация еще более усугубится в случае если приложение имеет много "окон" (и каждое "окно" может иметь более одной "оконной процедуры"). Очевидно, что количество массивов будет равно количеству "оконных процедур".
Аналогичная картина и по сообщениям WM_USERXXX. Как правило, эти сообщения делятся по группам и каждая группа имеет запас по кодам (для дальнейшего развития), следовательно, и здесь создавать сплошной массив затратно.
Применение массивов оправдано только в случае, когда создаются управляющие элементы (controls) диалогового окна. Здесь номера элементов можно (и нужно) задавать последовательно и применять массивы адресов, как наиболее эффективный способ перехода к обработчику события.
Ответить с цитированием
  (#24 (permalink)) Старый
Влад Влад вне форума
Специалист
 
Сообщений: 3,884
Сказал(а) спасибо: 1
Поблагодарили 25 раз(а) в 25 сообщениях
Регистрация: 27.06.2002
Адрес: Санкт-Петербург
По умолчанию 18.06.2003, 16:39

Ну, насчет того, что "никакой последовательности нет" - это ты перебощил, достаточно взглянуть на коды сообщений.
Что же касается компиляторов, то, по крайней мере, MSVC применяет три метода генерации кода для предложений типа switch(...) {...}:
а). генерация таблицы переходов (как приведено выше) - для последовательных идентификаторов,
б). генерация двух таблиц - идентификаторов и соответствующих им адресов переходов - для большого количества непоследовательных идентификаторов, и их выборку (кстати, очень эффективную),
в). уже приведенные тобою cmp ... ; je ... - для небольшого количества непоследовательных селекторов.
Причем, способ генерации кода выбирается компилятором автоматически, исходя из наибольшей скорости исполнения машинного кода. Когда я посмотрел, какой красивый код генерирует MSVC (а приведенные примеры - только небольшая часть), - я тихо повизгивал от восторга!
Ответить с цитированием
Ads
  (#25 (permalink)) Старый
Anonymous
Guest
 
Сообщений: n/a
По умолчанию Использование macro - 18.06.2003, 16:40

Рассмотрим пример автоматизации работа программиста на ассемблере по обработке сообщений. Повторю еще раз поставленные цели:
а) подбирали нужный алгоритм, исходя из количества обрабатываемых сообщений;
б) автоматически создавали необходимые структуры данных и код;
в) делали код программы более простым и наглядным.

Для решения перечисленных задач можно воспользоваться возможностями макроязыка. Представим заголовок макроопределения в виде (используется TASM Ideal):
Код:
macro   MSG_Jumper msg1, msg2:REST
...
endm    MSG_Jumper

; обращение к макроопределению будет иметь, например, такой вид:

MSG_Jumper      WM_CREATE, WM_DESTROY, WM_PAINT, WM_COMMAND, ...
Для того, чтобы подсчитать количество обрабатываемых сообщений можно сделать следующее:
Код:
macro   MSG_Counter     msg1, msg2:REST
        IFNB <msg1>
                @@MsgCount = @@MsgCount + 1
                MSG_Counter msg2       ; рекурсивный вызов макроопределения
        ENDIF
endm    MSG_Counter

macro   MSG_Jumper msg1, msg2:REST
        @@MsgCount      = 0
        MsgCounter msg1, msg2

       ; в данной точке MsgCount равен числу сообщений. Теперь можно выбрать алгоритм:
        IF MsgCount LE 5
               ; применяем первый алгоритм
        ELSEIF MsgCount LE 10
               ; применяем второй алгоритм
        ELSE
               ; применяем третий алгоритм
        ENDIF
        ...
endm    MSG_Jumper
Следующим шагом будет прописывание алгоритмов внутри макроопределения
Код:
macro   _Algo1          msg1, msg2:Rest
        IFNB <msg1>
                cmp     eax,msg1
                je      @@&msg1
                _Algo1  msg2
        ENDIF
endm    _Algo1

macro   Algo_First      msg1, msg2:REST
                mov     eax,[@@msg]
                _Algo1  msg1, msg2
endm    Algo_First

macro   _Algo2          msg1, msg2:REST
        IFNB <msg1>
                dd      msg1, @@&msg1
                _Algo2  msg2
        ENDIF
endm    _Algo2

macro   Algo_Second
LOCAL   @@1
DataSeg
LABEL   @@MSG_Array     dword
        _Algo2  msg1, msg2
CodeSeg
                mov     eax,[@@msg]
                mov     ecx,@@VecCount

@@1:            dec     ecx
                jz      @@default
                cmp     eax,[dword @@MSG_Array + ecx * 8]
                jne     @@1
                jmp      [dword @@MSG_Array + 4 + ecx * 8]
endm    Algo_Second

macro   _Algo3_1        msg1, msg2:REST
        IFNB <msg1>
                dd      msg1
                _Algo3_1 msg2
        ENDIF
endm    _Algo3_1

macro   _Algo3_2        msg1, msg2:REST
        IFNB <msg1>
                dd      @@&msg1
                _Algo3_2 msg2
        ENDIF
endm    _Algo3_2

macro   Algo_Third      msg1, msg2:REST
DataSeg
LABEL   @@MSG_ARRAY_1   dword
        _Algo3_1        msg1, msg2
LABEL   @@MSG_ARRAY_2   dword
        _Algo3_2        msg1, msg2
CodeSeg
                mov     eax,[@@msg]
                mov     ecx,@@VecCount - 1
                mov     edi,@@MSG_ARRAY_1
                cld
                repne   scasd
                jne      @@default
                sub     edi,@@MSG_Array_1
                jmp     [dword @@MSG_Array_2 + edi]
endm    Algo_Third

macro   MSG_Jumper msg1, msg2:REST
        @@MsgCount      = 0
        MsgCounter msg1, msg2

       ; в данной точке MsgCount равен числу сообщений. Теперь можно выбрать алгоритм:
        IF MsgCount LE 5
                Algo_First msg1, msg2
        ELSEIF MsgCount LE 10
                Algo_Second msg1, msg2
        ELSE
                Algo_Third msg1, msg2
        ENDIF
@@default:      call    DefWindowProc,  [@@hWnd], [@@msg], [@@wPar], [@@lPar]
@@ret:          ret
@@true:         mov     eax,1
                jmp     @@ret
@@false:        xor     eax,eax
                jmp     @@ret
endm    MSG_Jumper
Для того чтобы убедиться в том, что цели поставленные в начале сообщения достигнуты, можно посмотреть на то, как теперь происходит описание "оконной процедуры":
Код:
proc    myWndProc       stdcall
arg     @@hWnd  :dword, @@msg   :dword, @@wPar  :dword, @@lPar  :dword
MSG_Jumper      WM_CREATE, WM_COMMAND, WM_NOTIFY, WM_CLOSE

; теперь описываем сами обработчики сообщений
@@WM_CREATE:
               ; обрабатываем WM_CREATE
                jmp     @@true
@@WM_COMMAND:
               ; обрабатываем WM_COMMAND
                jmp     @@false
@@WM_NOTIFY:
               ; обрабатываем WM_NOTIFY
                jmp     @@false
@@WM_CLOSE:
               ; обрабатываем WM_CLOSE
                jmp     @@false
endp    myWndProc
Можно еще немного усовершенствовать код, добавив пару макроопределений, тогда код программы на ассемблере будет не менее читабелен, чем на ЯВУ, но при этом останется более эффективным и компактным.
Ответить с цитированием
  (#26 (permalink)) Старый
Anonymous
Guest
 
Сообщений: n/a
По умолчанию 18.06.2003, 23:39

Цитата:
Originally posted by Влад
[b]Ну, насчет того, что "никакой последовательности нет" - это ты перебощил, достаточно взглянуть на коды сообщений
Причем здесь коды сообщений? Речь шла об обработке сообщений. В какой программе обрабатываются только те сообщения, которые идут последовательно? Обрабатываются нужные сообщения, а они редко образуют последовательности. Мне такие случаи неизвестны.

Цитата:
Originally posted by Влад
[b]Что же касается компиляторов, то, по крайней мере, MSVC применяет три метода генерации кода для предложений типа switch(...) {...}
Было бы странно, если бы MS не заточила свои компиляторы под обработку switch-case. Суть постингов ASU в другом, он(а) показывает, как просто можно "заточить" ассемблер под задачу с помощью макросов. Мне лично очень понравились рекурсивные макросы. От того, что MSVC научился создавать хороший код для switch-case, программы не стали легче для разбора и понимания. А вот макро
Код:
MSG_Jumper      WM_CREATE, WM_COMMAND, WM_NOTIFY, WM_CLOSE
выглядит здорово. Очень надеюсь, что последует продолжение. ASU, не мог(ла) бы ты продолжить тему?
Ответить с цитированием
  (#27 (permalink)) Старый
Anonymous
Guest
 
Сообщений: n/a
По умолчанию 21.06.2003, 12:23

Цитата:
Originally posted by VicKool
[b]Очень надеюсь, что последует продолжение. ASU, не мог(ла) бы ты продолжить тему?
Собственно.. Все уже сказано. Можно "для красоты" добавить два макроопределения:
Код:
macro    MSG_HANDLER    Control, Message
    IFNB    <Message>
@@&Control&_&Message:
    ELSE
@@&Control:
    ENDIF
endm MSG_HANDLER

macro    END_HANDLER    distance, exit_code
    IFNB    <exit_code>
  jmp    distance @@&exit_code
    ELSE
  IFNB    <distance>
      jmp    @@&distance
  ENDIF
    ENDIF
endm    END_HANDLER
С помощью этих макроопределений повышается читабельность кода. Первое макроопределение просто подменяет метку (label), второе служит для завершения обработки. С этими макроопределениями, структура "оконной процедуры" примет вид:
Код:
proc    myWndProc       stdcall 
arg     @@hWnd  :dword, @@msg   :dword, @@wPar  :dword, @@lPar  :dword 
MSG_Jumper      WM_CREATE, WM_COMMAND, WM_NOTIFY, WM_CLOSE 

; теперь описываем сами обработчики сообщений 
MSG_HANDLER WM_CREATE
               ; обрабатываем WM_CREATE 
END_HANDLER ret_true

MSG_HANDLER WM_COMMAND
               ; обрабатываем WM_COMMAND
END_HANDLER ret_false

MSG_HANDLER WM_NOTIFY
               ; обрабатываем WM_NOTIFY
END_HANDLER ret_false

MSG_HANDLER WM_CLOSE: 
               ; обрабатываем WM_CLOSE 
END_HANDLER ret_false
endp    myWndProc
Макроопределения MSG_HANDLER и END_HANDLER обрамляют тело обработчика, выделяя из общего текста программы. Таким образом, программа, написанная на ассемблере, может быть не менее читаемой, чем программы, написанные на ЯВУ. Но при этом программы на ассемблере позволяют иметь большую производительность, меньший объем кода и, как указывалось ранее, более адекватное представление алгоритмов.
К сожалению в литературе, в том числе и учебной, макроопределениям уделяют незаслуженно мало внимания. В то время, как представить себе профессиональное использование ассемблера без макроопределений трудно. Макроопределения не только повышают читаемость программы, снижают трудоемкость создания программ (что для ассемблера критически важно), но и снижают возможность внесения ошибок.
Недооценка макроопределений совершенно незаслужена, это очевидно, если посмотреть на приемы нетривиального использования макроопределений. Ни один ЯВУ (насколько мне известно) не имеет столь развитого языка макроопределений. И при этом язык макроопределений используется редко и неэффективно... Досадно.
Ответить с цитированием
  (#28 (permalink)) Старый
_Cyclope _Cyclope вне форума
Member
 
Сообщений: 211
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
Регистрация: 15.06.2003
По умолчанию 05.07.2003, 12:53

Не осудите меня за дерзость, но я,например, изучал ассемблер отнюдь не ради програмирования--в своё время ну-очень любил я копаться с Windasm,Soft/winICE,h/qView. Тогда-то меня тянуло на злобные кряковские дела (какая радость была от взлома Tetris 3d, который усердно требовал пароля через 15 дней пользования. Впрочем радость от первой проги на асме куда как больше). А теперь я на асме лишь програмирую, чередуя с С/С++.Вот.
Ответить с цитированием
  (#29 (permalink)) Старый
Anonymous
Guest
 
Сообщений: n/a
По умолчанию 11.07.2003, 17:23

Программер не владеющий Ассемблером достоин жалости и сочуствия. потому что он только ДУМАЕТ, что он программер.

кроме того писать на асме - эстетическое удовольствие. если втянуться ))
Ответить с цитированием
  (#30 (permalink)) Старый
Anonymous
Guest
 
Сообщений: n/a
По умолчанию 20.07.2003, 11:37

Какая разница что говорят об ассемблере!!!
Меня он прет, но я же не выступаю с лозунгами.
Прогай себе на ASMе и забей на все остальное...
Ответить с цитированием
Ответ

Опции темы
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Trackbacks are Вкл.
Pingbacks are Вкл.
Refbacks are Выкл.


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Появилось окно с ошибкой: "Insert the "Tray App" disk and click OK". Anita_2 Техническая поддержка 6 14.12.2014 14:20
Ставлю систему "с нуля" после сбоя. Какие "работы" по тестированию железа полезны? russcand Любые вопросы от новичков 14 01.09.2011 00:27
Инструкция по адресу "0x436b10f" обратилась к памяти "0x03793dac". ВИРУС???? skazka Windows XP 5 21.03.2010 01:21
помогите выбрать "ASRock P4i45PE" или "GigaByte GA-8PE800" Константин Материнские платы 2 06.12.2009 15:21
Как исправить "attempt to store duplicate value in unique index "RDB$INDEX_5" ?" devo4ka-nimfetka Другие СУБД 1 16.04.2009 09:58
Закрываются игры, появляется ошибка: "0xbe8787ba" или "0x3e89ce89" . ASUSTeK Техническая поддержка 42 19.02.2009 01:38
После подключения кнопок "power" и "reset" компьютер перестал включаться. Лаборант-Шурупов Любые вопросы от новичков 1 25.01.2009 15:15
Добавить кнопки "свернуть" и "восстановить" к окну готового dialog-based приложения Lesat Visual C++ 2 07.01.2006 04:34
Как сделать чтобы вместо кнопок "Да" и "Нет" высвечивалось украинсие "Так" и "Ні" Форсаж Delphi 5 19.07.2003 19:30



Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.
Нardforum.ru - компьютерный форум и программирование, форум программистов