Желаете узнать ответ на свой вопрос как можно скорее? Посетите канал #russian на нашем Discord-сервере.
Написать комментарий
Скриншоты, содержащие элементы интерфейса, по общему правилу, удаляются сразу. Это же относится и к скриншотам, полученным с помощью Просмотрщика моделей или окна выбора персонажа.
Чем выше качество, тем лучше!
Перед загрузкой скриншота, пожалуйста, ознакомьтесь с требованиями, предъявляемыми к скриншотам!
Пожалуйста, введите ссылку на видеоролик в поле, указанное ниже.
Wowhead Client — это небольшая программа, с помощью которой мы поддерживаем базу данных в актуальном состоянии. Пользователи Wowhead Client получают доступ к дополнительным инструментам на сайте.
Две основные цели Wowhead Client:
Он устанавливает и обновляет аддон Wowhead Looter, который собирает данные, пока вы играете!
Он загружает собранные данные на Wowhead, помогая поддерживать базу данных в актуальном состоянии!
Вы также можете использовать Wowhead Client, чтобы просматривать выученные рецепты, выполненные задания, собранные ездовые животные и спутники и полученные звания!
УРОК 1. Знакомство с макросами / Как работать с макросами в Excel?
Источник: www.wowhead.com
Макросы
П еред тем как программа будет скомпилирована (или не будет, если найдены ошибки), текст программы обрабатывается препроцессором. Препроцессор позволяет изменять текст программы, используя специальные директивы.
Директива #define определяет новый макрос. Макрос, или макроподстановка, будет заменена в коде программы своим телом. Например, мы часто пользовались макросом
#define SIZE 20
и после этого использовали SIZE вместо размера массива.
Макрос может иметь любое допустимое имя и обычно его пишут прописными буквами для того, чтобы отличать от переменных и констант.
#define BREAK_WORD «end»
Макрос подставляется непосредственно в текст вашей программы. То есть, если у вас был код
#include #include #define LENGTH 128 void main()
то он будет заменён на код
#include #include void main()
Иными словами, макроподстановка — это просто подмена одного куска текста на другой.
Макросы могут иметь аргументы.
#define MAX (a, b) a > b ? a: b
#include #include #define MAX(x, y) x > y ? x: y void main()
Несмотря на то, что этот код работает, в нём есть ошибки. Макроподстановка – это именно подстановка:
#include #include #define MAX(x, y) x > y ? x: y void main()
Будет выведено
max number is 11
a = 11
b = 12 Это связано с тем, что код будет подменён следующим образом («max number is %dn», a++ > b++ ? a++: b++);
В данном случае возвращаемое значение будет ещё раз инкрементировано. Теперь рассмотрим макрос
#include #include #define SPHERE_VOLUME(r) 4,18879020 * (r) * (r) * (r) void main()
[Python] Макрос за 5 минут | Автоматизируем мышку и клавиатуру с помощью AutoGUI
С одной стороны, этот макрос должен делать программу быстрее, если заменить им вызов функции. Но на деле работать он будет медленнее. Макрос развернётся в следующий код
4,18879020 * (halfA + halfB) * (halfA + halfB) * (halfA + halfB)
итого, три раза будет вызвано сложение. Вот ещё пример ошибки
#include #include #define MUL(x, y) x * y void main()
В данном случае будет выведено 19 вместо 45, так как макрос будет раскрыт в выражение
2 + 3 * 4 + 5 == 2 + 12 + 5 == 19
Решением будет следующий макрос:
#include #include #define MUL(x, y) (x) * (y) void main()
И ещё одна ошибка, которая также встречается очень часто. Давайте напишем макрос, который будет выводить на печать массив. Мы воспользуемся им в сортировке пузырьком, чтобы видеть, как изменяется массив во время сортировки.
#include #include #define DISPLAY_ARRAY(arr, size) for (i = 0; i < size; i++) printf(«n»); #define SIZE 10 void main() < int a[SIZE] = ; int tmp; char flag, i; do < flag = 0; //Проходим по массиву. Если следующий элемент больше предыдущего, то //меняем их местами и по новой проверяем массив for (i = 1; i < SIZE; i++) < if (a[i] >a[i — 1]) < tmp = a[i]; a[i] = a[i — 1]; a[i — 1] = tmp; flag = 1; >DISPLAY_ARRAY(a, SIZE); > > while(flag); getch(); >
Этот пример работать не будет. Дело в том, что он использует переменную i, которая уже занята. Для корректной работы необходимо локализовать переменную. Для этого тело макроса нужно обернуть фигурными скобками и внутри задать переменную
#include #include #define DISPLAY_ARRAY(arr, size) printf(«n»); > #define SIZE 10 void main() < int a[SIZE] = ; int tmp; char flag, i; do < flag = 0; //Проходим по массиву. Если следующий элемент больше предыдущего, то //меняем их местами и по новой проверяем массив for (i = 1; i < SIZE; i++) < if (a[i] >a[i — 1]) < tmp = a[i]; a[i] = a[i — 1]; a[i — 1] = tmp; flag = 1; >DISPLAY_ARRAY(a, SIZE); > > while(flag); getch(); >
- 1. Всегда окружайте параметры круглыми скобками
- 2. Старайтесь передавать параметры явно и не передавать выражения, которые должны быть вычислены. Это будет приводить к неявным побочным эффектам и замедлению работы за счёт повторного выполнения кода.
- 3. Тело сложного макроса заносите под фигурные скобки.
Важно отметить ещё одну особенность языка. Строки в си ограничены двойными кавычками, но их можно конкатенировать просто написав рядом, например
int main(void)
Таким образом, можно объявлять макросы и использовать их следующим образом
#define SOME_TEXT «print number» #define PRINT_INT «%d» int main(void)
Условные конструкции
#ifdef #else #endif
Такая конструкция будет выполнять первую ветвь, если определён макрос с заданным именем. Например, таким образом можно создавать макрос, который будет выводить отладочную информацию.
#include #include #define DEBUG #ifdef DEBUG #define info(msg) printf(«%sn», msg) #else #define info(msg) #endif void main() < unsigned int bound, i, sum = 0; scanf(«%d», info(«step 1 finished»); for (i = 0; i < bound; i++) < sum += i; >info(«step 2 finished»); printf(«%d», sum); getch(); >
Если теперь ввести 12, то программа выведет
step 1 finished
step 2 finished
66
Если же удалить строку #define DEBUG , то будет выведено только
66
потому что сработает вторая ветвь условия и info(«строка») будет заменено на пустую строку.
Изменим макрос следующим образом
#define ON 1 #define OFF 0 #define DEBUG ON #if DEBUG == ON #define info(msg) printf(«%sn», msg) #else #define info(msg) #endif
Теперь вместо ifdef мы использовали директиву if , она в зависимости от условия выбирает первую или вторую ветвь. Также мы использовали макрос ON и OFF, а в дальнейшем использовали этот макрос в другом макросе. Это возможно, потому что первый макрос заменяется далее по ходу программы на своё тело. Так что первый макрос изменяет остальные макросы, а потом они уже вставляются далее в программу.
В этом примере, для того, чтобы отключить вывод сообщений, достаточно поменять строчку
#define DEBUG ON
#define DEBUG OFF
Кроме директивы #ifdef используется директива #ifndef (if not defined), он работает также, но первая ветвь работает только в случае, если макрос не определён. Также, как и с условными конструкциями, макрос может и не содержать ветви else.
Предопределённые макросы.
- __LINE__ — заменяется на текущую строку, в которой встречается этот макрос. Очень удобно для отлова ошибок – всегда можно возвращать не только сообщение об ошибке, но сразу же и номер строки.
- __FILE__ — имя текущего файла. Также очень удобно, в том случае, если программа состоит из множества файлов.
- __DATE__ — дата трансляции файла в формате Mmm dd yyyy . Если дата трансляции не может быть получена, то будет выведена какая-то действительная дата, в зависимости от реализации.
- __TIME__ — время трансляции файла в формате hh:mm:ss . Если время трансляции не может быть получено, то будет выведено какое-то действительное время, в зависимости от реализации.
- __STDC__ — макрос определён, если программа была откомпилирована с использованием стандарта ANSI С со включенной проверкой на совместимость. В противном случае __STDC__ не определен
#define ON 1 #define OFF 0 #define DEBUG ON #if DEBUG == ON #define err(msg) printf(«Error in %s at line %d: %sn», __FILE__, __LINE__, msg) #else #define err(msg) #endif
Использование препроцессора для инициализации объектов
В си директива include вставляет кусок кода в то место, где она указана. Это значит, что можно использовать директиву для начальной инициализации объектов, если, например, они слишком большие. Представленный ниже код валиден.
#include int main() < int a[] = < #include «./array.txt»; >; size_t i; for (i = 0; i < 10; i++) < printf(«%dn», a[i]); >_getch(); return 0; >
array.txt в той же директории
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
Макросы с переменным числом параметров
В С11 определён новый тип макросов – макросы с переменным числом параметров. Определяется он похоже на функции с переменным числом параметров. Обращение к параметрам происходит через макрос __VA_ARGS__. __VA_ARGS__ заменяется на переданные аргументы. Пример: имеется функция, собирающая односвязный список из массива.
typedef struct Node < int value; struct Node *next; >Node; void push(Node **head, int data) < Node *tmp = (Node*) malloc(sizeof(Node)); tmp->value = data; tmp->next = (*head); (*head) = tmp; > int pop(Node **head) < Node* prev = NULL; int val; if (head == NULL) < exit(-1); >prev = (*head); val = prev->value; (*head) = (*head)->next; free(prev); return val; > void fromArray(Node **head, int *arr, size_t size) < size_t i = size — 1; if (arr == NULL || size == 0) < return; >do < push(head, arr[i]); >while(i—!=0); >
Необходимо написать макрос, который бы собрал список, при этом количество параметров можно было изменять.
Функция fromArray получает три аргумента – указатель на узел, массив и его размер. Мы хотим избавиться от размера и массива. Тем не менее, всё равно придётся передавать тип массива, чтобы автоматически можно было изменять его размер.
#define fromArr(list, type, . ) ; fromArray( >
Макрос принимает два обязательных параметра – имя узла и название типа. Оставшихся параметров будет произвольное число, они перечисляются через запятую.
type xname[] = ;
внутри блока (области, ограниченной фигурными скобками) создаём массив и инициализируем его. При этом длина массива определяется автоматически.
fromArray(
Вызываем функцию, передавая ей в качестве аргументов указатель на узел, массив, который мы только что создали и размер. Так как тип массива известен и массив статический, то количество элементов находится элементарно.
Node *head = NULL; fromArr(head, int, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
таким образом, будет трансформирован в
< int xname[] = ; fromArray( >
Стрингизация и конкатенация макросов
Е сли во время создания макроса появилась необходимость в том, чтобы сделать из макроса строку или соединять макросы в один, то можно воспользоваться операторами # и ##. Оператор # превращает переданное значение в строку. Оператор ## соединяет элементы макроса.
Например, пусть у нас имеется структура, которая используется для парсинга комманд. Она состоит из строки (имени команды) и самой команды. При этом мы решили, что имя функции должно состоять из имени комманды плюс _command :
typedef struct command_tag < const char *name; void (*function) (void); >command_t; command_t commands[] = < < «quit», quit_command >, < «init», init_command >>;
Для сокращения кода можно объявить такой макрос
#define COMMAND(NAME)
Здесь #NAME превращает переданный параметр в строку, а NAME ## _command конкатенирует параметр с _command. Весь код:
#include #define COMMAND(NAME) < #NAME, NAME ## _command >void quit_command() < printf(«I am a quit commandn»); >void init_command() < printf(«I am a init commandn»); >typedef struct command_tag < const char *name; void (*function) (void); >command_t; #define SIZE 2 command_t commands[] = < COMMAND(quit), COMMAND(init), >; int main() < size_t i; for (i = 0; i < SIZE; i++) < printf(«%s says «, commands[i].name); commands[i].function(); >_getch(); return 0; >
Другой пример — макрос, который выводит на печать макрос.
#include #define STR(X) #X #define PRINT_MACROS(X) printf(«%s», STR(X)) #define EXAMPLE __somedata int main()
Этот макрос выведет на печать __somedata
Макросы — опасная штука. В них очень легко можно сделать ошибку, их сложно отлаживать и сопровождать. В этом курсе си, в общем-то, вам они совершенно не нужны (но врага надо знать в лицо). В то же время макросы — это мощный инструмент, который позволяет расширить возможности языка. Например, создание кроссплатформенных библиотек, или условная компиляция, которая зависит от железа.
Или такие изыски, как метод Даффа, позволяющий разматывать тело цикла, или реализация сопрограмм Саймоном Тетхемом.
Всё ещё не понятно? – пиши вопросы на ящик
Источник: learnc.info
26. Основы создания макросов в Assembler
После директивы пишется название макроса, а также может быть указан список параметров (операндов). Параметры в списке перечисляются через запятую. Внутри фигурных скобок записывается тело макроса. Кстати, для коротких макросов можно писать всё это в одной строке: macro <название_макроса>[] < > Тело макроса — это код, который подставляется в то место, где макрос будет вызван.
Создание макроса является по сути лишь его объявлением, в этом месте программы никакого кода сгенерировано не будет! Поэтому объявления макросов обычно размещают в самом начале программы или в отдельном файле.
Примеры макросов
В качестве примера рассмотрим простой макрос без параметров, который предназначен для завершения программы:
macro exit_app
После того, как макрос объявлен, в нужном месте программы достаточно написать exit_app. Туда препроцессор FASM автоматически подставит 2 команды, записанные в теле макроса. Создадим ещё один полезный макрос, предназначенный для такой часто используемой операции, как вывод строки:
macro print_str str
У этого макроса есть один параметр — адрес строки. При генерации кода вместо str будет подставлен тот параметр, который указан при вызове макроса. Обратите внимание, что код будет генерироваться в месте каждого вызова макроса! В этом главное отличие макроса от процедуры.
Код процедуры содержится в программе только в одном экземпляре, а вызывается она с помощью передачи управления командой CALL. Теперь добавим эти макросы в программу «hello, world!».
; Макрос выхода из программы macro exit_app < mov ax,4C00h ;Здесь только объявление макроса, код не генерируется int 21h >; Макрос вывода строки macro print_str str < mov ah,9 ;Здесь тоже код не генерируется mov dx,str int 21h >;——————————————————————————- use16 ;Генерировать 16-битный код org 100h ;Программа начинается с адреса 100h print_str hello ;Вывод строки exit_app ;Выход из программы ;——————————————————————————- hello db ‘Hello, macro world!$’
В результате основная программа состоит всего из двух строчек, и это уже не похоже на ассемблер, это — макроассемблер FASM.
Расширение системы команд
Макросы можно использовать для расширения системы команд. Например, часто в программе приходится обнулять регистры. Создадим специальный макрос для этой цели:
; Макрос — команда обнуления регистра macro clr reg < xor reg,reg >Теперь обнулять регистры в программе можно так: clr ax ;AX=0 clr si ;SI=0 clr bl ;BL=0
Макросы с переменным количеством параметров
Возможно также создавать макросы с переменным количеством параметров. В этом случае имя параметра записывается в квадратных скобках. Для генерации кода макрос вызывается столько раз, сколько параметров ему было передано. Например, можно написать специальные макросы для улучшения команд PUSH и POP:
; Макрос — улучшенная команда push macro push [arg] < push arg >; Макрос — улучшенная команда pop macro pop [arg]
Несмотря на то, что название макроса совпадает с именем команды, в теле макроса это имя считается именем команды (иначе получилась бы бесконечная рекурсия ). Данные макросы позволяют помещать в стек и извлекать из стека сразу несколько операндов, что упрощает код программы. Пример использования:
push ax,word[si],5 pop dx,cx,ax
В результате препроцессором будет сгенерирован следующий код:
push ax push word[si] push 5 pop dx pop cx pop ax
Директива include
Возможно, вам захочется написать собственный набор макросов и использовать их в своих программах. В этом случае удобно поместить макросы в отдельный файл и воспользоваться директивой включения файла include.
Синтаксис директивы include очень прост: include ‘путь/к/файлу’ Путь к файлу указывается в одинарных кавычках и может быть относительным (по отношению к компилируемому файлу) или полным (начиная от буквы диска или корневого каталога системы). Если включаемый файл находится в той же папке, то достаточно указать только имя файла. Расширение файла может быть любым, но обычно используют «inc» или «asm». Препроцессор FASM читает указанный файл и подставляет код из него вместо директивы include. В отдельный файл можно также вынести часто используемые процедуры, отдельные функциональные блоки программы или даже объявления данных. Если записать макросы в отдельный файл ‘mymacro.inc’, то программа «hello, world!» станет ещё короче:
include ‘mymacro.inc’ use16 ;Генерировать 16-битный код org 100h ;Программа начинается с адреса 100h print_str hello ;Вывод строки exit_app ;Выход из программы ;——————————————————————————- hello db ‘Hello, macro world!$’
Упражнение
Напишите макрос для определения максимального значения. У макроса должно быть 3 операнда: второй и третий сравниваются между собой, больший из них помещается на место первого. Результаты можете писать в комментариях или на форуме.
Предыдущий урок | Список уроков | Следующий урок |
Источник: pro-prof.com