Директивы препроцессора, модульное программирование

Содержание

Слайд 2

Директива #include

Директива #include позволяет включать в текст программы содержимое указанного файла:
#include <имя_файла>
Если файл является заголовочным

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

Слайд 3

Директива #define

Директива #define позволяет вводить в текст программы макроопределения:
#define <идентификатор> <замена>
Директива указывает компилятору, что нужно подставить строку, определенную

Директива #define Директива #define позволяет вводить в текст программы макроопределения: #define Директива
как Замена, вместо каждого аргумента Идентификатор в исходном файле. Замена не действует для строковых констант или на части более длинного идентификатора. Имена макроопределений принято писать БОЛЬШИМИ_БУКВАМИ.

Слайд 4

В зависимости от значения константы компилятор присваивает ей тот или иной тип.

В зависимости от значения константы компилятор присваивает ей тот или иной тип.
С помощью суффиксов можно переопределить тип константы:
U или u представляет целую константу в беззнаковой форме (unsigned);
F (или f) позволяет описать вещественную константу типа float;
L (или l) позволяет выделить целой константе 8 байт (long long int);

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

Слайд 5

#define <имя>(<аргумент1>[, ..., <аргументN>]) <замена>
После определения макроса каждое последующее вхождение замещается версией аргумента замена,

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

Слайд 6

Однако при использовании таких макроопределений следует соблюдать осторожность:

Однако при использовании таких макроопределений следует соблюдать осторожность:

Слайд 7

Оператор ## в директиве #define берет два отдельных токена и вставляет их

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

Слайд 8

По умолчанию текст макроопределения должен размещаться на одной строке.
Если требуется перенести

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

Слайд 9

Директива #undef

Директива #undef отменяет предыдущее макроопределение:

Директива #undef Директива #undef отменяет предыдущее макроопределение:

Слайд 10

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

Директивы #if или #ifdef / #ifndef вместе с директивами #elif, #else и #endif управляют компиляцией исходного файла.
Если указанное выражение

Условная компиляция Директивы #if или #ifdef / #ifndef вместе с директивами #elif,
после #if имеет ненулевое значение, в записи преобразования сохраняется группа строк, следующая сразу за директивой #if. Синтаксис условной директивы следующий:
#if <константное выражение>    <группа операций> #elif <константное выражение>    <группа операций> #else    <группа операций> #endif

Слайд 11

Отличие директив #ifdef и #ifndef от #if заключается в том, что константное выражение

Отличие директив #ifdef и #ifndef от #if заключается в том, что константное
может быть задано только с помощью #define. У каждой директивы #if должна быть соответствующая закрывающая директива #endif.
Между ними может располагаться любое кол-во директив #elif, но не более одной директивы #else, которая должна быть последней.

Слайд 12

Модульное программирование

Модульное программирование — это организация программы как совокупности небольших независимых блоков,

Модульное программирование Модульное программирование — это организация программы как совокупности небольших независимых
называемых модулями.
Модуль — функционально законченный отдельно-компилируемый фрагмент программы, оформленный в виде отдельного файла с исходным кодом. 
Модуль в языке С состоит из интерфейса (заголовочого файла .h) и реализации (файла .c).
Код, подключающий модуль, на этапе компиляции нуждается только в интерфейсе модуля, поэтому на этапе препроцессинга заголовочный файл копируется в код директивой #include "module.h"
Реализация модуля должна полностью реализовывать указанный интерфейс, поэтому она также включает свой заголовочный файл.

Слайд 13

В данном примере в файле main.c не понадобилось подключать stdio.h, хотя он и используется в

В данном примере в файле main.c не понадобилось подключать stdio.h, хотя он
модуле testlib.c, т.к. никакие типы из stdio.h не нужны для корректной обработки интерфейса  testlib.h, оказывающегося в main.c на этапе компиляции.
Если бы это было не так, то библиотеки должны были бы быть включены не в  testlib.c, а в  testlib.h, чтобы во всех местах, где подключается модуль testlib, и все нужные заголовочные файлы включались автоматически.

Слайд 14

После компиляции мы получили два объектных файла модулей *.o, которые представляют собой

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

Слайд 15

Глобальные переменные

Поскольку С позволяет выполнять раздельную компиляцию модулей для большой программы в

Глобальные переменные Поскольку С позволяет выполнять раздельную компиляцию модулей для большой программы
целях ускорения компиляции и помощи управлению большими проектами, должны быть способы передачи информации о глобальных переменных файлам программы. Решение заключается в объявлении глобальных переменных в одном файле и использовании при объявлении в других файлах ключевого слова extern:

Слайд 16

Спецификатор extern сообщает компилятору, что следующие за ним типы и имена переменных

Спецификатор extern сообщает компилятору, что следующие за ним типы и имена переменных
объявляются где-то в другом месте. Extern позволяет компилятору знать о типах и именах глобальных переменных без действительного создания этих переменных. Когда два модуля объединяются, все ссылки на внешние переменные пересматриваются.
Если при объявлении выделяется память под переменную, то процесс называется определением. Использование extern приводит к объявлению, но не к определению. Оно просто говорит компилятору, что определение происходит где-то в другом месте программы.

Слайд 17

Статические переменные

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

Статические переменные Статические переменные являются долговременными переменными, существующими на протяжении функции или
Они отличаются от глобальных переменных, поскольку не известны за пределами функции или файла, но могут хранить свои значения между вызовами.
Различают статические локальные и статические глобальные переменные.
Когда модификатор static применяется к локальной переменной, это приводит к тому, что компилятор создает долговременную область для хранения переменной почти также, как это делается для глобальной переменной.
Ключевое различие между статической локальной и глобальной переменными заключается в том, что статическая локальная переменная остается известной только в том блоке, в котором она была объявлена. Т.е. статическая локальная переменная - это локальная переменная, сохраняющая свое значение между вызовами функций.

Слайд 19

Когда спецификатор static применяется к глобальной переменной, он сообщает компилятору о необходимости

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

Файл main.c:

Файл func.c:

Слайд 20

Объявление типа

Язык С позволяет определять имена новых типов данных с помощью ключевого

Объявление типа Язык С позволяет определять имена новых типов данных с помощью
слова typedef. На самом деле здесь не создается новый тип данных, а определяется новое имя существующему типу. Он позволяет облегчить создание машинно-независимых программ. Единственное, что потребуется при переходе на другую платформу, - это изменить оператор typedef. Он также может помочь документировать код, позволяя назначать содержательные имена стандартным типам данных:
typedef <тип> <имя>;
где тип — это любой существующий тип данных, а имя - это новое имя для данного типа. Новое имя определяется в дополнение к существующему имени типа, а не замещает его. Использование typedef может помочь при создании более легкого для чтения и более переносимого кода.
Имя файла: Директивы-препроцессора,-модульное-программирование.pptx
Количество просмотров: 42
Количество скачиваний: 0