Главная страница
Навигация по странице:

  • Индивидуальное задание на тему: «Применение директив препроцессора С++. Использование данных.»

  • 3.2.2. Формальное описание макроподстановок

  • 3.2.3. Пример раскрытия макроопределения

  • Применение директив препроцессора С . Использование данных. Реферат практика1. Применение директив препроцессора С. Использование данных. 5


    Скачать 55.26 Kb.
    НазваниеПрименение директив препроцессора С. Использование данных. 5
    АнкорПрименение директив препроцессора С . Использование данных.
    Дата30.04.2022
    Размер55.26 Kb.
    Формат файлаdocx
    Имя файлаРеферат практика1.docx
    ТипОтчет
    #505755


    Отчет

    по производственной практике
    ПМ. 01 «Разработка программных модулей программного обеспечения компьютерных систем»

    (Название профессионального модуля)
    Тема индивидуального задания:
    «Применение директив препроцессора С++. Использование данных.»


    СОДЕРЖАНИЕ


    ВВЕДЕНИЕ 3

    Индивидуальное задание на тему: «Применение директив препроцессора С++. Использование данных.» 5

    1. Основные функции препроцессора 5

    2. Синтаксис директив 6

    3. Описание директив 7

    3.1. Вставка файлов (#include) 7

    3.2. Константы и макросы #define 8

    3.2.1. Операторы # и ## 10

    3.2.2. Формальное описание макроподстановок 10

    3.2.3. Пример раскрытия макроопределения 13

    3.3. Предопределённые константы #define 14

    3.4. Условная компиляция 15

    4. Диграфы и триграфы 17

    ВЫВОДЫ ПО ПРАКТИКЕ 18

    СПИСОК ЛИТЕРАТУРЫ 19


    ВВЕДЕНИЕ


    В период с 24 ноября по 28 декабря 2018 года я проходил производственную практику.

    Результатом освоения практики является приобретение общих и профессиональных компетенций (ОК и ПК):

    Общие компетенции:


    Код

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

    ОК 1.

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

    ОК 2.

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

    ОК 3.

    Принимать решения в стандартных и нестандартных ситуациях и нести за них ответственность.

    ОК 4.

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

    ОК 5.

    Использовать информационно-коммуникационные технологии в профессиональной деятельности.

    ОК 6.

    Работать в коллективе и в команде, эффективно общаться с коллегами, руководством, потребителями.

    ОК 7.

    Брать на себя ответственность за работу членов команды (подчиненных), за результат выполнения заданий.

    ОК 8.

    Самостоятельно определять задачи профессионального и личностного развития, заниматься самообразованием, осознанно планировать повышение квалификации.

    ОК 9.

    Ориентироваться в условиях частой смены технологий в профессиональной деятельности.



    Профессиональные компетенции:


    Вид проф. деятельности

    Код

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


    Разработка программных модулей программного обеспечения компьютерных систем

    ПК 1.1

    Выполнять разработку спецификаций отдельных компонент.

    ПК 1.1

    Осуществлять разработку кода программного продукта на основе готовых спецификаций на уровне модуля.

    ПК 1.3

    Выполнять отладку программных модулей с использованием специализированных программных средств.

    ПК 1.4

    Выполнять тестирование программных модулей.

    ПК 1.5

    Осуществлять оптимизацию программного кода модуля.

    ПК 1.6

    Разрабатывать компоненты проектной и технической документации с использованием графических языков спецификаций.

    Для достижения вышеназванных результатов, за время прохождения производственной практики мною были выполнены следующие работы:

    знакомство с местом прохождения производственной практики;

    разработка алгоритма поставленной задачи и реализация его средствами автоматизированного проектирования;

    разработка кода программного продукта на основе готовой спецификации на уровне модуля;

    использование инструментальных средств на этапе отладки программного продукта;

    проведение тестирования программного модуля по определенному сценарию.

    Индивидуальное задание на тему: «Применение директив препроцессора С++. Использование данных.»



    1. Основные функции препроцессора


    Препроцессором выполняются следующие действия:

    • замена соответствующих диграфов и триграфов на эквивалентные символы «#» и «\»;

    • удаление экранированных символов перевода строки;

    • замена строчных и блочных комментариев пустыми строками (с удалением окружающих пробелов и символов табуляции);

    • вставка (включение) содержимого произвольного файла (#include);

    • макроподстановки (#define);

    • условная компиляция (#if, #ifdef, #elif, #else, #endif);

    • вывод сообщений (#warning, #error).

    Условная компиляция позволяет выбрать код для компиляции в зависимости от:

    • модели процессора (платформы);

    • разрядности адресов;

    • размерности типов;

    • наличия/отсутствия поддержки расширений языка;

    • наличия/отсутствия библиотек и/или функций;

    • особенностей поведения конкретных функций;

    • и другого.

    Этапы работы препроцессора:

    • лексический анализ кода C/C++ (синтаксический анализ не выполняется);

    • обработка директив;

    • выполнение подстановок:

    • диграфов и триграфов;

    • комментариев;

    • директив;

    • лексем, заданных директивами.

    Язык препроцессора C/C++ не является полным по Тьюрингу хотя бы потому, что с помощью директив невозможно заставить препроцессор зависнуть. См. рекурсивная функция (теория вычислимости).

    2. Синтаксис директив


    Директивой (командной строкой) препроцессора называется строка в исходном коде, имеющая следующий формат: #ключевое_слово параметры:

    • ноль или более символов пробелов и/или табуляции;

    • символ #;

    • одно из предопределённых ключевых слов;

    • параметры, зависимые от ключевого слова.

    Список ключевых слов:

    • define — создание константы или макроса;

    • undef — удаление константы или макроса;

    • include — вставка содержимого указанного файла;

    • if — проверка истинности выражения;

    • ifdef — проверка существования константы или макроса;

    • ifndef — проверка не существования константы или макроса;

    • else — ветка условной компиляции при ложности выражения if;

    • elif — проверка истинности другого выражения; краткая форма записи для комбинации else и if;

    • endif — конец ветки условной компиляции;

    • line — указание имени файла и номера текущей строки для компилятора;

    • error — вывод сообщения и остановка компиляции;

    • warning — вывод сообщения без остановки компиляции;

    • pragma — указание действия, зависящего от реализации, для препроцессора или компилятора;

    • если ключевое слово не указано, директива игнорируется;

    • если указано несуществующее ключевое слово, выводится сообщение об ошибке и компиляция прерывается. (В некоторых компиляторах, Таких как g++, компиляция продолжается, просто показывая предупреждение)

    3. Описание директив

    3.1. Вставка файлов (#include)


    При обнаружении директив #include "..." и #include <...>, где «…» — имя файла, препроцессор читает содержимое указанного файла, выполняет директивы и замены (подстановки), заменяет директиву #include на директиву #line и обработанное содержимое файла.

    Для #include "..." поиск файла выполняется в текущей папке и папках, указанных в командной строке компилятора. Для #include <...> поиск файла выполняется в папках, содержащих файлы стандартной библиотеки (пути к этим папкам зависят от реализации компилятора).

    При обнаружении директивы #include последовательность-лексем не совпадающей ни с одной из предыдущих форм, рассматривает последовательность лексем как текст, который в результате всех макроподстановок должен дать #include <...> или #include "...". Сгенерированная таким образом директива далее будет интерпретироваться в соответствии с полученной формой.

    Включаемые файлы обычно содержат:

    • объявления функций;

    • объявления глобальных переменных;

    • определения интерфейсов;

    • определения типов данных;

    • и другое.

    Директива #include обычно указывается в начале файла (в заголовке), поэтому включаемые файлы называются заголовочными.

    Пример включения файлов из стандартной библиотеки языка C.

    #include // включение объявлений математических функций

    #include // включение объявлений функций ввода-вывода

    Использование препроцессора считается неэффективным по следующим причинам:

    • каждый раз при включении файлов выполняются директивы и замены (подстановки); компилятор мог бы сохранять результаты препроцессирования для использования в будущем;

    • множественные включения одного файла приходится предотвращать вручную с помощью директив условной компиляции; компилятор мог бы выполнять эту задачу самостоятельно.

    Начиная с 1970-х годов стали появляться способы, заменившие включение файлов. В языках Java и Common Lisp используются пакеты (ключевое слово package) (см. package в Java), в языке Паскальангл. units (ключевые слова unit и uses), в языках Modula, OCaml, Haskell и Python — модули. В языке D, разработанном для замены языков C и C++, используется ключевые слова module и import.

    3.2. Константы и макросы #define


    Константы и макросы препроцессора используются для определения небольших фрагментов кода.

    // константа

    #define BUFFER_SIZE ( 1024 )

    // макрос

    #define NUMBER_OF_ARRAY_ITEMS( array ) ( sizeof( array ) / sizeof( *(array) ) )

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

    Пример. Определение макроса max, принимающего два аргумента: a и b.

    #define max( a, b ) ( (a) > (b) ? (a) : (b) )

    Макрос вызывается так же, как и любая функция.

    z = max( x, y );

    После замены макроса код будет выглядеть следующим образом:

    z = ( (x) > (y) ? (x) : (y) );

    Однако, наряду с преимуществами использования макросов в языке Си, например, для определения обобщённых типов данных или отладочных инструментов, они также несколько снижают эффективность их применения и даже могут привести к ошибкам.

    Например, если f и g — две функции, вызов

    z = max( f(), g() );

    не вычислит один раз f()и один раз g(), и поместит наибольшее значение в z, как этого можно было ожидать. Вместо этого одна из функций будет вычислена дважды. Если функция имеет побочные эффекты, то вероятно, что её поведение будет отличаться от ожидаемого.

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

    Некоторые современные языки обычно не используют такой способ метапрограммирования с использованием макросов как дополнений строк символов, в расчете или на автоматическое или на ручное подключение функций и методов, а вместо этого другие способы абстракции, такие как шаблоны, обобщённые функции или параметрический полиморфизм. В частности, встраиваемые функции[en] позволяют избежать одного из главных недостатков макросов в современных версиях Си и C++, так как встроенная функция обеспечивает преимущество макросов в снижении накладных расходов при вызове функции, но её адрес можно передавать в указателе для косвенных вызовов или использовать в качестве параметра. Аналогично, проблема множественных вычислений, упомянутая выше в макросе max, для встроенных функций неактуальна.

    Константы #define можно заменить на enum, а макросы — на функции inline.

    3.2.1. Операторы # и ##


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

    #define make_str( bar ) # bar

    printf( make_str( 42 ) );

    препроцессор преобразует в:

    printf( "42" );

    Оператор ## в макросах объединяет две лексемы, например:

    #define MakePosition( x ) x##X, x##Y, x##Width, x##Height

    int MakePosition( Object );

    препроцессор преобразует в:

    int ObjectX, ObjectY, ObjectWidth, ObjectHeight;

    3.2.2. Формальное описание макроподстановок


    1) Управляющая строка следующего вида заставляет препроцессор заменять идентификатор на последовательность лексем везде далее по тексту программы:

    #define идентификатор последовательность_лексем

    При этом символы пустого пространства в начале и в конце последовательности лексем выбрасываются. Повторная строка #define с тем же идентификатором считается ошибкой, если последовательности лексем не идентичны (несовпадения в символах пустого пространства не играют роли).

    2) Строка следующего вида, где между первым идентификатором и открывающей круглой скобкой не должно быть символов пустого пространства, представляет собой макроопределение с параметрами, задаваемыми списком-идентификаторов.

    #define идентификатор (список_идентификаторов) последовательность_лексем

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

    Управляющая строка следующего вида приказывает препроцессору «забыть» определение, данное идентификатору:

    #undef идентификатор

    Применение директивы #undef к не определенному ранее идентификатору не считается ошибкой.

    {

    • Если макроопределение было задано во второй форме, то любая следующая далее в тексте программы цепочка символов, состоящая из идентификатора макроса (возможно, с последующими символами пустого пространства), открывающей скобки, списка лексем, разделенных запятыми, и закрывающей скобки, представляет собой вызов макроса.

    • Аргументами вызова макроса являются лексемы, разделенные запятыми, причем запятые, взятые в кавычки или вложенные круглые скобки, в разделении аргументов не участвуют.

    • (!)Во время группировки аргументов раскрытие макросов в них не выполняется.

    • Количество аргументов в вызове макроса должно соответствовать количеству параметров макроопределения.

    • После выделения аргументов из текста символы пустого пространства, окружающие их, отбрасываются.

    • Затем в замещающей последовательности лексем макроса каждый идентификатор-параметр, не взятый в кавычки, заменяется на соответствующий ему фактический аргумент из текста.

    • (!)Если в замещающей последовательности перед параметром не стоит знак #, если и ни перед ним, ни после него нет знака ##, то лексемы аргумента проверяются на наличие в них макровызовов; если таковые есть, то до подстановки аргумента в нём выполняется раскрытие соответствующих макросов.

    На процесс подстановки влияют два специальных знака операций.

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

    • Перед каждым символом " или \, встречающимся вокруг или внутри строковой или символьной константы, автоматически вставляется обратная косая черта.

    • Во-вторых, если последовательность лексем в макроопределении любого вида содержит знак ##, то сразу после подстановки параметров он вместе с окружающими его символами пустого пространства отбрасывается, благодаря чему сцепляются соседние лексемы, образуя тем самым новую лексему.

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

    • Кроме того, знак ## не может стоять ни в начале, ни в конце замещающей последовательности лексем.

    }

    • (!)В макросах обоих видов замещающая последовательность лексем повторно просматривается в поиске новых define-идентификаторов.

    • (!)Однако если какой-либо идентификатор уже был заменен в текущем процессе раскрытия, повторное появление такого идентификатора не вызовет его замены; он останется нетронутым.

    • (!)Даже если развернутая строка макровызова начинается со знака #, она не будет воспринята как директива препроцессора.

    Восклицательным знаком (!) отмечены правила, отвечающие за рекурсивные вызов и определения.

    3.2.3. Пример раскрытия макроопределения


    #define cat( x, y ) х ## у

    Вызов макроса «cat(var, 123)» будет заменён на «var123». Однако вызов «cat(cat(1, 2), 3)» не даст желаемого результата. Рассмотрим шаги работы препроцессора:

    0: cat( cat( 1, 2 ), 3 )

    1: cat( 1, 2 ) ## 3

    2: cat( 1, 2 )3

    Операция «##» помешала правильному раскрытию аргументов второго вызова «cat». В результате получилась следующая цепочка лексем:

    cat ( 1 , 2 )3

    где «)3» — результат сцепления последней лексемы первого аргумента с первой лексемой второго аргумента, не является допустимой лексемой.

    Можно задать второй уровень макроопределения в таком виде:

    #define xcat( x, y ) cat( x, y )

    Вызов «xcat(xcat(1, 2), 3)» будет заменён на «123». Рассмотрим шаги работы препроцессора:

    0: xcat( xcat( 1, 2 ), 3 )

    1: сat( xcat( 1, 2 ), 3 )

    2: cat( cat( 1, 2 ), 3 )

    3: cat( 1 ## 2, 3 )

    4: cat( 12, 3 )

    5: 12 ## 3

    6: 123

    Всё прошло благополучно, потому что в раскрытии макроса «xcat» не участвовал оператор «##».

    Многие статические анализаторы не умеют правильно обрабатывать макросы, поэтому качество статического анализа снижается[источник не указан 885 дней].

    3.3. Предопределённые константы #define


    Константы, создаваемые препроцессором автоматически:

    • __LINE__ заменяется на номер текущей строки; номер текущей строки может быть переопределен директивой #line; используется для отладки;

    • __FILE__ заменяется на имя файла; имя файла тоже может быть переопределено с помощью директивы #line;

    • __FUNCTION__ заменяется на имя текущей функции;

    • __DATE__ заменяется на текущую дату (на момент обработки кода препроцессором);

    • __TIME__ заменяется на текущее время (на момент обработки кода препроцессором);

    • __TIMESTAMP__ заменяется на текущие дату и время (на момент обработки кода препроцессором);

    • __COUNTER__ заменяется на уникальное число, начиная от 0; после каждой замены число увеличивается на единицу;

    • __STDC__ заменяется на 1, если компиляция происходит в соответствии со стандартом языка C;

    • __STDC_HOSTED__ определена в C99 и выше; заменяется на 1, если выполнение происходит под управлением ОС;

    • __STDC_VERSION__ определена в C99 и выше; для C99 заменяется на число 199901, а для C11 — на число 201112;

    • __STDC_IEC_559__ определена в C99 и выше; константа существует, если компилятор поддерживает операции с числами с плавающей точкой по стандарту IEC 60559;

    • __STDC_IEC_559_COMPLEX__ определена в C99 и выше; константа существует, если компилятор поддерживает операции с комплексными числами по стандарту IEC 60559; стандарт C99 обязывает поддерживать операции с комплексными числами;

    • __STDC_NO_COMPLEX__ определена в C11; заменяется на 1, если не поддерживаются операции с комплексными числами;

    • __STDC_NO_VLA__ определена в C11; заменяется на 1, если не поддерживаются массивы переменной длины; в С99 массивы переменной длины обязательно должны поддерживаться;

    • __VA_ARGS__ определена в C99 и позволяет создавать макросы с переменным числом аргументов.

    3.4. Условная компиляция


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

    В общем случае, программисту необходимо использовать конструкцию типа:

    # ifndef FOO_H

    # define FOO_H

    ...(код заголовочного файла)...

    # endif

    Такая «защита макросов» предотвращает двойное подключение заголовочного файла путём проверки существования этого макроса, который имеет то же самое имя, что и заголовочный файл. Определение макроса FOO_H происходит, когда заголовочный файл впервые обрабатывается препроцессором. Затем, если этот заголовочный файл вновь подключается, FOO_H уже определен, в результате чего препроцессор пропускает полностью текст этого заголовочного файла.

    То же самое можно сделать, включив в заголовочный файл директиву:

    # pragma once

    Условия препроцессора можно задавать несколькими способами, например:

    # ifdef x

    ...

    # else

    ...

    # endif
    Или
    # if x

    ...

    # else

    ...

    # endif

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

    Большинство современных языков программирования не используют такие возможности, больше полагаясь на традиционные операторы условия if...then...else..., оставляя компилятору задачу извлечения бесполезного кода из компилируемой программы.

    4. Диграфы и триграфы


    Препроцессор обрабатывает диграфы «%:» («#»), «%:%:» («##») и триграфы «??=» («#»), «??/» («\»).

    Препроцессор считает последовательность «%:%:» двумя токенами при обработке кода C и одним токеном при обработке кода C++.

    ВЫВОДЫ ПО ПРАКТИКЕ


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

    Данная практика позволила приобрести практический опыт в:

    разработке алгоритма поставленной задачи и реализации его средствами автоматизированного проектирования;

    разработке кода программного продукта на основе готовой спецификации на уровне модуля;

    использовании инструментальных средств на этапе отладки программного продукта;

    проведении тестирования программного модуля по определенному сценарию.


    СПИСОК ЛИТЕРАТУРЫ


    1. Альфред, В. Ахо Компиляторы. Принципы, технологии и инструментарий / Альфред В. Ахо и др. - Москва: Высшая школа, 2015. - 882 c.

    2. Балена, Франческо Современная практика программирования на Microsoft Visual Basic и Visual C# / Франческо Балена , Джузеппе Димауро. - М.: Русская Редакция, 2015. - 640 c.

    3. Боровский, А. C++ и Pascal в Kylix 3. Разработка интернет-приложений и СУБД / А. Боровский. - М.: БХВ-Петербург, 2015. - 544 c.

    4. Давыдов, В. Visual C++. Разработка Windows-приложений с помощью MFC и API-функций / В. Давыдов. - М.: БХВ-Петербург, 2014. - 576 c.

    5. Довбуш, Галина Visual C++ на примерах / Галина Довбуш , Анатолий Хомоненко. - М.: БХВ-Петербург, 2012. - 528 c.

    6. Зиборов, В. MS Visual C++ 2010 в среде .NET / В. Зиборов. - М.: Питер, 2012. - 320 c.

    7. Кетков, Юлий Практика программирования: Visual Basic, C++ Builder, Delphi. Самоучитель (+ дискета) / Юлий Кетков , Александр Кетков. - М.: БХВ-Петербург, 2012. - 464 c.

    8. Мешков, А. Visual C++ и MFC / А. Мешков, Ю. Тихомиров. - М.: БХВ-Петербург, 2013. - 546 c.

    9. Неформальное введение в C++ и Turbo Vision. - Москва: ИЛ, 2010. - 384 c.

    10. Панюкова, Т. А. Языки и методы программирования. Создание простых GUI-приложений с помощью Visual С++. Учебное пособие / Т.А. Панюкова, А.В. Панюков. - Москва: Мир, 2015. - 144 c.

    11. Пахомов, Б. C/C++ и MS Visual C++ 2010 для начинающих / Б. Пахомов. - М.: БХВ-Петербург, 2011. - 736 c.

    12. Пахомов, Борис C/C++ и MS Visual C++ 2012 для начинающих / Борис Пахомов. - Москва: СИНТЕГ, 2015. - 518 c.

    13. Пахомов, Борис С/С++ и MS Visual C++ 2012 для начинающих / Борис Пахомов. - М.: "БХВ-Петербург", 2013. - 502 c.

    14. Полубенцева, М. C/C++. Процедурное программирование / М. Полубенцева. - М.: БХВ-Петербург, 2014. - 448 c.

    15. Поляков, А. Методы и алгоритмы компьютерной графики в примерах на Visual C++ / А. Поляков, В. Брусенцев. - М.: БХВ-Петербург, 2011. - 560 c.

    16. Понамарев, В. Программирование на C++/C# в Visual Studio .NET 2003 / В. Понамарев. - М.: БХВ-Петербург, 2015. - 917 c.

    17. Роберт, С. Сикорд Безопасное программирование на C и C++ / Роберт С. Сикорд. - Москва: РГГУ, 2014. - 496 c.

    18. Секунов, Н. Программирование на C++ в Linux / Н. Секунов. - М.: БХВ-Петербург, 2016. - 425 c.

    19. Сидорина, Татьяна Самоучитель Microsoft Visual Studio C++ и MFC / Татьяна Сидорина. - М.: "БХВ-Петербург", 2014. - 848 c.


    написать администратору сайта