Excel предоставляет огромное количество функций для автоматизации вычислений и обработки данных. Однако сфера деятельности человека очень широка, и встроенной функциональности не всегда достаточно. Да, даже если он очень большой. В таких случаях положение спасают макросы.
Они значительно повышают эффективность работы с информацией. Дело в том, что они не только помогают реализовать некоторые функции, отсутствующие в стандартном комплекте, но и автоматизируют часто повторяющиеся действия. Сегодня мы подробнее рассмотрим, что такое макросы, как они работают, как создавать новые макросы и редактировать старые.
Что такое макрос и для чего он применяется
Итак, макрос — это набор команд, которые необходимо выполнить Excel. Они позволяют автоматизировать практически все повторяющиеся задачи. Просто выберите команду один раз, используя комбинацию горячих клавиш или панель инструментов.
Макросы написаны с использованием языка программирования VBA, но вы можете написать простой макрос и без него. Технически она ничем не отличается от программы, поскольку содержит набор инструкций, которым компьютер должен следовать. Часто макрос сравнивают с рецептом, который также описывает последовательность, в которой нужно выполнить какие действия, чтобы получить желаемый результат.
КАК СОЗДАВАТЬ МАКРОСЫ НА МЫШКЕ BLOODY
Но между макросом и рецептом есть принципиальная разница. Макрос запускается один раз, после чего все остальные действия выполняются вручную. Поэтому, если использовать метафоры кулинарии, ее проще сравнить с мультиваркой, в которую достаточно один раз положить необходимые ингредиенты, после чего блюдо будет приготовлено самостоятельно.
Инструкции, переданные в макрос, содержат инструкции макроса, особые команды, которые должен выполнить офисный пакет. Некоторые из них специфичны, но большинство соответствуют командам в главном меню. Это сделано для того, чтобы сделать процесс создания макроса более удобным для пользователя.
Возьмем пример. Любое приложение, независимо от используемой операционной системы, содержит кнопку «Закрыть». Если мы хотим сделать это с помощью макроса, нам нужно вставить команду ActiveWindow.Close в среду разработки. Вы можете видеть, что многое понимаете по названиям операторов, поскольку все они написаны на английском языке. Это также упрощает задачу для пользователя, знающего английский язык.
Вам не нужно бояться макросов, потому что VBA — очень простой язык программирования. Большинство действий можно запрограммировать, даже не написав ни единой строчки кода. Эти действия достаточно один раз записать. Важно помнить, что редактор кода намного функциональнее, чем визуальные методы написания макросов.
Как создать новый макрос в Excel
Как мы уже выяснили, есть два способа записи макросов в Excel: ручной или автоматический. Для использования последнего метода не требуются навыки программирования. Правда, он ограничен и не дает возможности записывать условия, формировать сложные циклы и так далее.
Как создать макросы в Microsoft Access за 7 минут
Поэтому для профессионального владения электронными таблицами программирование просто необходимо. На самом деле очень часто, кроме написания кода напрямую, невозможно каким-либо образом решить поставленные задачи.
Способ 1. Автоматический запуск макроса
Перед записью макросов необходимо произвести ряд простых настроек, в первую очередь включить сами макросы. Правда, на данном этапе неопытный пользователь может столкнуться с некоторыми трудностями. Дело в том, что настройки макроса находятся во вкладке «Разработчик», доступ к которой изначально закрыт. Следовательно, вам необходимо сначала включить эту функцию. Последовательность действий следующая:
- Найдите меню «Файл» и щелкните его левой кнопкой мыши.
- Затем появится экран с рядом подпунктов. Нам нужно выбрать меню «Параметры».
- Далее находим пункт «Настроить ленту» и ищем флажок, который активирует вкладку «Разработчик».
- Подтверждаем свои действия нажатием кнопки «ОК».
Далее мы увидим вкладку «Разработчик» в нашей программе. Сделаем по нему переход. Перед нами предстает большое количество инструментов разработчика. Из всего этого ассортимента нам интересна группа «Код». Есть небольшая кнопка «Записать макрос», после нажатия на которую производится прямая запись данной программы.
После этого пользователь увидит диалоговое окно. Из него вы можете установить параметры для нашей будущей подпрограммы. Здесь доступны следующие настройки:
- Имя макроса. Вы можете использовать любое имя, кроме того, которое начинается с цифры или символа. В этом случае вы не можете использовать более одного слова в качестве имени.
- Комбинация клавиш. Это тип триггера для макроса. Он используется для включения макросов. Все горячие клавиши начинаются с клавиши Ctrl, причем последнюю можно настроить самостоятельно. Например, вы можете использовать горячую клавишу r. Также можно ввести заглавную букву. Для этого нужно использовать клавишу Shift, которая автоматически добавляется к комбинации горячих клавиш.
- Складские услуги. По умолчанию макрос применяется к текущей книге. Однако пользователь может выбрать новый или создать свою собственную книгу макросов.
- Описание. При желании пользователь может несколькими предложениями описать, что будет делать макрос. Это будет особенно полезно, если одну книгу используют несколько человек.
После выполнения всех действий нужно нажать кнопку ОК, тем самым подтвердив изменения. Теперь все действия, выполняемые пользователем, будут автоматически записываться в макрос. Это будет продолжаться ровно до тех пор, пока запись программы не будет остановлена. Разобраться в этом гораздо проще на реальном примере. Создадим программу, которая умножает содержимое двух ячеек.
Для этого нужно начать запись макроса, ввести в ячейку формулу (в нашем случае это = B2 * B3), нажать клавишу Enter, затем остановить запись. Кнопка остановки записи макроса находится на вкладке «Разработчик» в группе «Код».
Запуск выполнения макроса
Как мы можем проверить, работает ли наш макрос? Для этого выполните следующие действия:
- Откройте вкладку «Разработчик». Там, крайний слева, есть кнопка «Макрос», которую нужно один раз нажать левой кнопкой мыши. Также пользователь может открыть аналогичный вариант, нажав горячие клавиши Alt + F8.
- Далее мы откроем окно для настройки макросов. Вы должны выбрать тот, который мы только что создали, и нажать кнопку «Выполнить». Того же результата можно достичь, нажав сочетание клавиш, которое мы назначили макросу ранее.
- О том, что макрос работает, мы можем судить по действиям программы. Если они повторяют то, что делали раньше, то все в порядке.
Таким образом можно управлять любым макросом. Но что, если окажется, что он не работает так, как нам нужно?
Корректировка макроса
Если есть проблемы с запуском макроса, их можно исправить. Наиболее распространенная проблема, при которой команды не выполняются должным образом, — это ошибки пользователя на этапе начальной регистрации команды. Чтобы отредактировать созданный макрос, вам необходимо сделать следующее.
- Откройте окно макроса, нажав ту же кнопку, описанную выше, или используйте комбинацию клавиш.
- Выберем наш макрос. Находим кнопку «Изменить», которая находится справа от нее. Сделаем по нему один щелчок левой кнопкой мыши.
- Откроется редактор Visual Basic. В код необходимо будет внести изменения, поэтому, если у вас нет навыков программирования, вам нужно быть очень осторожным при записи макроса.
На этом этапе вам нужно немного перейти к следующей теме: ручное редактирование макроса. Любой макрос начинается с подкоманды. Компьютер распознает, что макрос заканчивается командой End Sub. Имя макроса появляется после слова Sub. Затем в структуру записывается описание макроса и комбинация клавиш, необходимая для его выполнения.
Далее следуют команды, выполняющие определенные действия. Например, мы получаем номер ячейки с помощью оператора Range. В нашем примере мы получаем ячейку B2 с помощью команды Range («B2»). Это действие аналогично выделению ячейки левой кнопкой мыши. Текущее выбранное значение ячейки указывается с помощью оператора ActiveCell.FormulaR1C1.
Попробуем немного подправить наш макрос. Допустим, вам необходимо выполнить следующую задачу: добавить дополнительную ячейку с адресом B4 и значением 3. В этом случае добавьте в код следующие строки:
Дальность («В4»). Выбирать
На первый взгляд это может показаться довольно сложной задачей, но команды на самом деле представляют собой законченный язык, который просто необходимо выучить. Представьте себе, что вы пишете сообщение не только человеку, но и компьютеру с просьбой сделать то или это. Да, программирование действительно такое. Все намного проще, чем кажется.
Но это уже лирическое отступление. У нас все еще есть действие: изменить исходное выражение, относящееся к ячейке D2, на следующее: ActiveCell.FormulaR1C1 = «= RC [-2] * R [1] C [-2] * R [2] C [- 2]»
Внимание! Мы видим, что адреса в ячейках в этом примере записываются как R1C1.
После выполнения всех шагов, описанных выше, вы можете закрыть редактор макросов. Для этого достаточно нажать на крестик. То есть выполнять действия, аналогичные закрытию любого окна в операционной системе.
Далее вам нужно еще раз перепроверить макрос. Мы видим, что после его выполнения в таблице появилась еще одна ячейка. Если макрос очень большой, ручное редактирование имеет много преимуществ перед перезаписью. Также избегайте повторных ошибок.
Вы также можете ускорить выполнение макроса, добавив команду Application.ScreenUpdating = False. После этого на экране не будут отображаться те промежуточные шаги, которые выполняет макрос, только конечный результат. Если вы хотите, чтобы отображение экрана было снова включено, вам нужно заменить False на True.
Способ 2. Создание макроса в ручном режиме
Автоматическая запись макроса — это здорово, но у этого метода много недостатков. Профессионалы создают макросы вручную. Для этого вам необходимо выучить язык VBA и выполнить следующие действия:
- Перейдите на вкладку «Разработчик» и нажмите кнопку «Visual Basic». Он находится в крайнем левом углу панели инструментов на этой вкладке.
- После этого появится окно, которое мы уже знаем из предыдущего раздела.
- Здесь написан весь код.
Следует отметить, что рассмотреть все детали сегодня не удастся, так как для этого нужно знать язык VBA. Однако общий механизм таков. А освоив язык VBA, вы уже можете изучать более сложные языки программирования, поскольку логика написания макроса такая же, как и для написания полноценных компьютерных программ.
Как изменять существующие макросы
Подробности о том, как изменить существующие макросы, были описаны выше. В общем, логика остается той же, за исключением того, что макро коррекция — это изменение точки (например, изменение ячейки, если она была случайно выбрана неправильно). В то время как изменение — это наиболее фундаментальное редактирование, включая добавление новых строк кода и так далее.
Заключение
Что такое макросы
Макросы в Си: как, когда и зачем?
Программисты Си, дойдя до определённого уровня квалификации, обязательно сталкиваются с одной из особенностей этого языка — макросами. Почти во всех других языках аналога макросов нет. И это неспроста. Использование макросов может оказаться весьма небезопасным. В них скрывается ряд особенностей, специфика которых не всегда лежит на поверхности.
Прим. перев. Макросы в таких языках, как Lisp, Scala и Rust, во многом лишены тех проблем и недостатков, которые описаны в этой статье.
Макросы и функции
При первом знакомстве макросы могут показаться обычными вызовами функций. Конечно, у них немного странный синтаксис, но они «ведут себя» как обычные функции. Тогда в чём разница?
Макрос можно условно назвать функцией обработки и замены программного кода: после сборки программы макросы заменяются макроопределениями. Вот как это выглядит:
#include #define SUM(x, y) (x + y) int main(int argc, char *argv[])
Этот код преобразуется в следующий:
/* обработанный код опущен */ int main(int argc, char *argv[])
При вызове же функции под неё выделяется новый стековый кадр, и она выполняется самостоятельно и не зависит от места в коде, откуда была вызвана. Таким образом, переменные с одинаковыми именами в разных функциях не вызовут ошибку, даже если вызывать одну функцию из другой.
#include void bar() < int var = 10; printf(«var in bar: %dn», var); >void foo() < int var = 5; printf(«var in foo: %dn», var); bar(); >int main(int argc, char *argv[])
Но если попытаться проделать такой же трюк с помощью макроса, то во время компиляции будет выброшена ошибка, так как обе переменные в итоге будут находиться в одной функции:
#include #define bar() int var = 10; printf(«var in bar: %dn», var) void foo() < int var = 5; printf(«var in foo: %dn», var); bar(); >int main(int argc, char *argv[])
Один из способов решить эту проблему — поместить тело макроса в новую область видимости имён:
#include #define bar() < int var = 10; printf(«var in bar: %dn», var); >void foo() < int var = 5; printf(«var in foo: %dn», var); bar(); >int main(int argc, char *argv[])
Но если просто обернуть его в блок, то может возникнуть такая проблема: блок, в который раскроется использование bar , и стоящая после него точка с запятой будут учтены как две разные команды, и в результате, встретив else , компилятор выдаст ошибку.
Простым решением было бы не ставить после использования такого макроса точку с запятой, но тогда программисту потребовалось бы помнить о необходимости ставить или не ставить точку с запятой для каждого макроса.
Обычно эту проблему решают с помощью такого трюка:
#include #define bar() do < int var = 10; printf(«var in bar: %dn», var); >while (0) int main(int argc, char *argv[])
Такой цикл выполнится только один раз, но поскольку конструкция do-while в Си требует точки с запятой после условия, стоящая после макроса точка с запятой будет отнесена к нему, а не воспринята как отдельная команда.
Более того, функции выполняют проверку типов: если функция ожидает на входе строку, а получает число, будет выброшена ошибка (или, по крайней мере, предупреждение, в зависимости от компилятора). Макросы в то же время просто заменяют аргумент, который им передан.
И, наконец, макросы не подлежат отладке. В отладчике можно войти в функцию и пройтись по её коду, а вот с макросами такое не пройдёт. Поэтому, если макрос почему-то сбоит, единственный способ выявить проблему — переходить к его определению и разбираться уже там.
Прим. перев. Чтобы не переходить к определению каждого макроса, можно попросить компилятор раскрыть макросы — это можно сделать с помощью команды gcc -E source.c . Имейте в виду, что если вы включаете в свой код с помощью #include стандартные заголовочные файлы, после препроцессинга в коде может оказаться много тысяч строк, так что стоит перенаправить вывод компилятора в файл.
Тем не менее, можно выделить одно явное преимущество макросов перед функциями — производительность. Макрос быстрее, чем функция. Как уже упоминалось выше, под функцию выделяются дополнительные ресурсы, которые можно сэкономить, если использовать макросы. Это преимущество может сыграть весомую роль в системах с ограниченными ресурсами (например, в очень старых микроконтроллерах). Но даже в современных системах программисты производят оптимизации, используя макросы для небольших процедур.
Прим. перев. Интересный подход к оптимизации использования ресурсов в программе на Си рассмотрен в другой нашей статье.
В C99 и C++ существует альтернатива макросам — встраиваемые (inline) функции. Если добавить ключевое слово inline перед функцией, компилятору будет дано указание включить тело функции в место её вызова (по аналогии с макросом). При этом встраиваемые функции могут быть отлажены, и у них есть проверка типов.
Однако ключевое слово inline — это просто подсказка для компилятора, а не строгое правило, и компилятор может проигнорировать эту подсказку. Чтобы этого не произошло, в gcc есть атрибут always_inline , который заставляет компилятор встроить функцию.
Встраиваемые функции — отличная штука, которая, как может показаться, делает использование макросов нецелесообразным. Однако это не совсем так.
Когда использовать макросы в Cи
Передача аргументов по умолчанию
В C++ есть весьма удобный инструмент, которого нет в Си, — аргументы по умолчанию:
#include using namespace std; void printError(int errorCode, string msg = «No message») < cerr int main(int argc, char *argv[])
В Си задача опциональных аргументов может быть решена с помощью макросов:
#include #define printErrord(errorCode) printError(errorCode, «No message») void printError(int errorCode, char *msg) < printf(«Error code: %d (%s)n», errorCode, msg); >int main(int argc, char *argv[])
Этот код довольно безопасен и не скрывает никаких подводных камней (их мы обсудим далее). Конечно, эту задачу можно также решить с помощью функции, но она достаточно тривиальна, чтобы нести накладные расходы при использовании функций. Макрос справляется с ней на ура.
Использование отладочных строк
Некоторые компиляторы предопределяют макросы, которые нельзя использовать в функциях: __FILE__ , __LINE__ , __func__ .
Их можно включать в определения макросов, используемых для отладки:
#include #define log_info(M, . ) fprintf(stderr, «[INFO] (%s:%d) » M «n», __FILE__, __LINE__, ##__VA_ARGS__) int main(int argc, char *argv[])
В итоге получается интересный способ ведения логов.
Модификация синтаксиса
Это очень мощная особенность макросов. Используя её, можно создать свой собственный синтаксис.
Например, в Cи нет конструкции foreach . Но её можно создать через макрос:
#include struct ListNode; typedef struct ListNode < struct ListNode *next; struct ListNode *prev; void *value; >ListNode; typedef struct List < int count; ListNode *first; ListNode *last; >List; #define LIST_FOREACH(curr, list) ListNode *curr = list->first; for (ListNode *_node = list->first; _node != NULL; curr = _node = _node->next) int main(int argc, char *argv[]) < List *lst; /* Fill the linked list */ LIST_FOREACH(curr, lst) < printf(«%dn», (int)curr->value); > >
В этой вставке кода определена структура, содержащая связный список. Предполагая, что его узлы заполнены, можно пройтись по нему с помощью LIST_FOREACH так же, как и при использовании foreach в современных языках.
Эта техника действительно очень эффективна и при правильном использовании может дать довольно хорошие результаты.
Другие типы макросов
Помимо макросов, которые подменяют функции, есть и другие очень полезные директивы препроцессора. Вот некоторые из наиболее часто используемых:
- #include — включить содержимое стороннего файла в текущий файл,
- #ifdef — задать условие для компиляции,
- #define — определить константу (и, конечно же, макрос).
#ifdef играет ключевую роль при создании заголовочных файлов. Использование этого макроса гарантирует, что заголовочный файл включён только один раз:
#ifndef MACROS_IN_C_H #define MACROS_IN_C_H /* Прототипы функций */ #endif // MACROS_IN_C_H
Стоит отметить, что основное предназначение #ifdef — условная компиляция блоков кода на основе некоторого условия. Например, вывод отладочной информации только в режиме отладки:
#include #ifdef DEBUG #define log_info(M, . ) fprintf(stderr, «[INFO] (%s:%d) » M «n», __FILE__, __LINE__, ##__VA_ARGS__) #else #define log_info(M, . ) #endif int main(int argc, char *argv[])
Прим. перев. С помощью #ifdef также довольно часто задаётся условие для компиляции на различных версиях ОС и архитектурах: #ifdef _WIN32 , #ifdef _WIN64 , #ifdef __linux__ и так далее.
Как правило, для определения констант используется #define , но в некоторых проектах его заменяют на const и перечисления ( enum ). Однако при использовании любой из этих альтернатив есть свои преимущества и недостатки.
Использование ключевого слова const , в отличие от макроподстановки, позволяет произвести проверку типов данных. Но в Cи это создаёт не совсем полноценные константы. Например, их нельзя использовать в операторе switch-case и для определения размера массива.
Прим. автора В C++ переменные, определённые ключевым словом const , являются полноценными константами (их можно использовать в приведённых выше случаях), и настоятельно рекомендуется использовать именно их, а не #define .
Перечисления в то же время — полноценные константы. Они могут использоваться в операторах switch-case и для определения размера массива. Однако их недостаток заключается в том, что в перечислениях можно использовать только целые числа. Их нельзя использовать для строковых констант и констант с плавающей запятой.
Вот почему использование #define — оптимальный вариант, если нужно достичь единообразия в определении различного рода констант.
Таким образом, у макросов есть свои преимущества. Но использовать их нужно весьма аккуратно.
Подводные камни при использовании макросов
Отсутствие скобок
Наиболее распространённая ошибка, которую допускают при использовании макросов, — отсутствие скобок вокруг аргументов в определениях макросов. Поскольку макросы подставляются непосредственно в код, это может вызвать неприятные побочные эффекты:
#include #define MULTIPLY(x) (x * 5) int main(int argc, char *argv[])
В этом примере выполняется вычисление MULTIPLY(x + 5) и ожидаемый результат — 50. Но в процессе подстановки произойдёт следующее преобразование:
MULTIPLY(x + 5) -> (x + 5 * 5)
Как несложно подсчитать, данное выражение выдаст не 50, а 30.
А вот как выполнить данную задачу правильно:
#include #define MULTIPLY(x) ((x) * 5) int main(int argc, char *argv[])
Инкремент и декремент
Допустим, есть такой код:
#include #define ABS(x) ((x)
Здесь можно ожидать, что x будет увеличен на единицу и будет равен 6, а результат — 5. Но вот что получится в реальной жизни:
Виновата всё та же макроподстановка: ABS(x++) -> ((x++) < 0 ? — (x++): (x++))
Как видно, x увеличивается на единицу в первый раз при проверке и во второй раз при определении результата, что и приводит к соответствующим итогам.
Передача вызовов функций
Использованием функции в коде никого не удивишь. Равно как и передачей результата одной функции в виде аргумента для другой. Часто это делается так:
#include int bar() < return 10; >void foo(int num) < printf(«%dn», num); >int main(int argc, char *argv[])
И в этой вставке кода всё в порядке. Но, когда это же производится с помощью макроса, можно столкнуться с серьёзными проблемами производительности. Допустим, есть вот этот код:
#include #define MIN(a, b) ((a) < (b) ? (a) : (b)) int sum_chars(char *chars) < if ((*chars) == ‘