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

Презентация:



Advertisements
Похожие презентации
Обработка исключительных ситуаций Исключительная ситуация (исключение) – это ошибка, возникающая во время выполнения программы. Например, ошибка работы.
Advertisements

Условная компиляция Условная компиляция C / С++Pascal Условная компиляция выполняется с помощью специальных директив и позволяет выборочно компилировать.
Лекция 10 Препроцессор. Препроцессор языка Си Препроцессор работает на первом шаге компиляции. Директивы препроцессора: #include#define#undef #ifdef#if#else.
Лекция 9 Приведение типов. Классификация типов Типы С++ Пользовательские Встроенные (Фундаментальные) Адресные Арифтметические void Указатели Ссылки Массивы.
Лекция 8 Область видимости Время жизни. Область видимости Область видимости – характеристика именованного объекта Область видимости - часть текста программы,
Препроцессор языка Си Препроцессор языка Си предназначен для внесения изменений в исходный текст программы непосредственно перед ее компиляцией, а также.
Октябрь Макрообработка (2 часа). Октябрь Основные вопросы Основные понятия. Классификация макропроцессоров. Основные понятия. Классификация.
Основы языка программирования. План лекций: 1.Основные особенности языка С++ 2. Основные понятия языка программирования: алфавит, константы, идентификаторы,
Инструкции C++ Условная инструкция Формат: if (условие) оператор; else оператор; Пример: if (i!=0) { if (j) j++; if(k) k++; else if(p) k--; } else i--;
Лекция 6 Функции. Объявления и определения Объявление функции – указание имени функции, а также входных и выходных параметров Определение функции – указание.
Лекция 3 ПЕРВЫЕ ПРОГРАММЫ, ВВОД/ВЫВОД В ЯЗЫКЕ С++
Лекция 1 Введение в программирование и язык C. Машинный код Машинный код или машинный язык система команд (набор кодов операций) конкретной вычислительной.
Лекция 6 Функции. Объявления и определения Объявление функции – указание имени функции, а также входных и выходных параметров Определение функции – указание.
Функции Функция – именованная последовательность описаний и операторов, выполняющая некоторое действие. Может иметь параметры и возвращать значение. Функция.
Лабораторная работа 7. Работа с динамической памятью, строками и файлами.
Преобразования типов В языке C/C++ имеется несколько операций преобразования типов. Они используются в случае, если переменная одного типа должна рассматриваться.
ЛАБОРАТОРНАЯ РАБОТА 1 ПРОЕКТИРОВАНИЕ И РЕАЛИЗАЦИЯ ТАБЛИЦ, ИСПОЛЬЗУЕМЫХ В ТРАНСЛЯТОРЕ Рейн Т. С.
Основы информатики Лекция. Директивы. Исключения Заикин Олег Сергеевич
Синтаксис языка Java. Символы и синтаксис Перевод строчки эквивалентен пробелу Регистр в именах различается.
Лекция 21. Шаблоны (часть 1) Красс Александр СПбГУ ИТМО, 2008.
Транксрипт:

Лекция 7 Модульность

Причины модульности Структурированность Данные, разделенные по отдельным файлам проще поддаются структурированию, анализу и навигации Абстракция и сокрытие реализации Возможность использования функций без указания их реализации Возможность создания библиотек Частичная компиляция Наличие «промежуточного формата» и этапа «связывания» позволяет проводить компиляцию только части проекта

Последовательность сборки Препроцессирование Обработка включаемых файлов и директив компилятора Подготовка «чистого» кода Компиляция Синтаксическая и семантическая обработка Трансляция реализаций в машинные коды Компоновка Связывание имен и реализаций Подготовка конечного исполнимого файла Исходный код *.c,*.h, *.cpp,*.hpp Единица трансляции *.i Единица трансляции *.i Промежуточный файл *.obj Исполнимый файл *.exe, *.dll, *.lib Препроцессирование Компиляция Компоновка

Препроцессор + Компилятор (Compiler) Фактическая схема file1.cpp common.h file1.h file3.h file2.h file2.cpp file3.cpp file1.obj file2.obj file3.obj Компоновщик (Linker) file.exe

Препроцессирование

Этапы препроцессирования Начальное процессирование Подготовка текста программы к разбору Лексический разбор (токенизация) Разбиение текста программы на лексические единицы (лексемы или токены) – ключевые слова, имена, операторы. Подстановка Включение заголовочных файлов, условная компиляция, раскрытие макросов

Начальное процессирование Чтение файла в память Файл прочитывается как последовательность байт Разбиение на строки Последовательность байт разбивается на последовательность строк. Разделителями являются принятые в ОС символы (CR,LF,CR LF) Подстановка триграфов и диграфов Тройные символы типа ??/ заменяются на \ Склеивание «разбитых» строк Строка, заканчивающаяся символом \, присоединяет к себе следующую строку Замена комментариев на пробелы Однострочные комментарии от // до конца строки Многострочные комментарии от /* до первого появления */

Скрытые ловушки Склеивание комментариев Вложенные комментарии int f = 9 ; // What the f, David Blaine????????/ f = 12 ; int f = 9 ; // What the f, David Blaine????????/ f = 12 ; /* I dont need this int f () { /* Nobody needs this */ int a = 9 ; } */ /* I dont need this int f () { /* Nobody needs this */ int a = 9 ; } */

Лексический разбор (токенизация) Разделение по whitespace Whitespace (пробельными) символами являются символы пробела, табуляции и переноса строки «Жадный» разбор в неоднозначных случаях В неоднозначных случаях выбирается допустимая лексема максимальной длины. Например a+++b будет разобрано как a ++ + b Сообщение об ошибке, если лексема не принадлежит языку Например, в случае ` и т.п. a a b b

Макроподстановка Включение заголовочных файлов Директивы (команды) комилятору Подстановка макросов Условная компиляция #include#if#ifdef #pragma#else #ifndef #define#elif #undef#endif #error #include#if#ifdef #pragma#else #ifndef #define#elif #undef#endif #error

Включение заголовочных файлов Полное включение Директива #include полностью замещается текстом включаемого файла в текущей единице трансляции. Поиск стандартных заголовочных файлов Заголовочный файл ищется среди списка каталогов стандартных библиотек путем добавления к ним пути в угловых скобках. Поиск локальных заголовочных файлов Аналогично предыдущему, но в начало поиска добавлюятся каталоги с файлом, в котором указана директива, а также «каталоги дополнительного включения». #include #include "file.h"

Специальные директивы Директива генерации ошибки Генерация ошибки с текстовым сообщением. Используется при условной компиляции (например, чтобы сообщить о неподдерживаемых компиляторе или платформе). Директива компилятора Специфична для каждого компилятора. Используется для управления поведением компилятора. #error message #pragma command parameters #pragma once #pragma warning ( 4290:disable ) #pragma pack (push,1) #pragma pack (pop) #pragma comment ( lib, libpng.lib" ) #pragma once #pragma warning ( 4290:disable ) #pragma pack (push,1) #pragma pack (pop) #pragma comment ( lib, libpng.lib" )

Макросы Непараметризованный макрос Указывает препроцессору, что в дальнейшем коде следует заменять лексему name на соответствующий текст text. Параметризованный макрос Указывает препроцессору, что в дальнейшем коде следует заменять последовательность лексем name(параметры) на текст text, в котором лексемы-параметры заменяются аргументы макроса Отмена макроса Отменяет дальнейшую подстановку имени #undef name #define name text #define name(x,y) x+y

Примеры #define NULL 0 int * t = NULL ; // int * t = 0 ; int BERNULLY = 8 ; // Нет подстановки const char p[] = NULL ; // Нет подстановки #define test() hell test()o // hell o, а не hello #define max(a,b) ((a)>(b)?(a):(b)) //директивы компилятора всегда однострочны! #define max_fn(type) type max ( type x, type y )\ { \ return max( x,y ); \ } #define NULL 0 int * t = NULL ; // int * t = 0 ; int BERNULLY = 8 ; // Нет подстановки const char p[] = NULL ; // Нет подстановки #define test() hell test()o // hell o, а не hello #define max(a,b) ((a)>(b)?(a):(b)) //директивы компилятора всегда однострочны! #define max_fn(type) type max ( type x, type y )\ { \ return max( x,y ); \ }

Макрооператоры # и ## Преобразование в строку Параметр шаблона преобразуется в строку (заключается в кавычки) Конкатенация лексем Две лексемы-имени, между которыми находится символ ##, соединяются в одну #define as_str(x) # x printf ( as_str(c u l 8 r)); // printf("c u l 8 r"); #define as_str(x) # x printf ( as_str(c u l 8 r)); // printf("c u l 8 r"); #define infix(x) x ## _ ## x infix(O) // O_O infix(o O) // o O_o O #define as_instr(x) Who #x are as_instr ( you ) // Who you are #define infix(x) x ## _ ## x infix(O) // O_O infix(o O) // o O_o O #define as_instr(x) Who #x are as_instr ( you ) // Who you are

Недостатки макросов Отсутствие типизации Досинтаксическая подстановка #define max(a,b) a > b ? a : b max (7,Hello) max (7,int) max (7,Hello) max (7,int) int a = max (7,2); // int a = 7 > 2 ? 7 : 2 ; int b = max (7,2)+4; // int b = 7 > 2 ? 7 : ; #undef max #define max(a,b) ((a) > (b) ? (a) : (b)) int c=max(a++,++b);//int c=(a++)>(++b)?(a++):(++b); int a = max (7,2); // int a = 7 > 2 ? 7 : 2 ; int b = max (7,2)+4; // int b = 7 > 2 ? 7 : ; #undef max #define max(a,b) ((a) > (b) ? (a) : (b)) int c=max(a++,++b);//int c=(a++)>(++b)?(a++):(++b);

Условная компиляция #define DEBUG #define MSVC_VER 0500 #if 0 printf (yet another commented line); #endif #if defined(DEBUG) #define MODE Debuggy #elif MSVC_VER < 0500 #define MODE Ye olde #else #define MODE Whatever #endif #define DEBUG #define MSVC_VER 0500 #if 0 printf (yet another commented line); #endif #if defined(DEBUG) #define MODE Debuggy #elif MSVC_VER < 0500 #define MODE Ye olde #else #define MODE Whatever #endif

Условная компиляция #define DEBUG #if defined(DEBUG) printf (debug); #else printf (release); #endif #ifdef DEBUG printf (debug); #endif #ifndef DEBUG printf (release); #endif #define DEBUG #if defined(DEBUG) printf (debug); #else printf (release); #endif #ifdef DEBUG printf (debug); #endif #ifndef DEBUG printf (release); #endif

Компиляция

Этапы компиляции Синтаксический анализ Выделение инструкций, проверка их синтаксиса Семантический анализ Разрешение имен, соответствие типов, приоритет операций и т.п. Трансляция в машинный код Перевод содержимого функций единицы трансляции в машинные коды с сохранением имен и прототипов. Все исользуемые имена на этом этапе должны быть объявлены, но могут не быть определены. Результатом компиляции является промежуточный («объектный») файл, содержащий откомпилированный код и таблицу имен всех объектов, доступных в этой единице трансляции. Код может содержать символические ссылки на неразрешенные имена (определенные, например, в других единицах трансляции).

Компоновка

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

Внутренняя и внешняя компоновка Внешняя компоновка Имя, которое может быть использовано в других единицах трансляции, считается именем со внешней компоновкой Ко внешним данным относятся: Глобальные переменные (объявленные вне функций) Функции Глобальные пользовательские типы Все остальное – внутренние данные int a ; void * b ; enum S { A, B }; void foo () { int c = 9 ; } int a ; void * b ; enum S { A, B }; void foo () { int c = 9 ; }

Ключевое слово extern Используется как модификатор при объявлениях переменных Применяется только к глобальным объектам Указывает, что объект определен в другой единице компиляции int a ; // определена в этой единице extern int b ; // определена в другой единице extern int c = 9 ; // extern теряет смысл – c определено extern int sum(int,int); // необязательно int a ; // определена в этой единице extern int b ; // определена в другой единице extern int c = 9 ; // extern теряет смысл – c определено extern int sum(int,int); // необязательно

Ключевое слово static В контексте глобальных объектов ключевое слово static означает внутреннюю компононовку объекта. int a ; // определена в этой единице extern int b ; // определена в другой единице static int c = 9 ; // определена в этой единице // допускает объявление глобального // имени c в другой единице static int max(int,int); // прототип функции с внутренней // компоновкой int a ; // определена в этой единице extern int b ; // определена в другой единице static int c = 9 ; // определена в этой единице // допускает объявление глобального // имени c в другой единице static int max(int,int); // прототип функции с внутренней // компоновкой

Правило одного определения ODR (One Definition Rule) Каждый объект (тип, переменная, функция) должен быть определен только один раз. При этом ему может предшествовать любое количество идентичных объявлений. Решение при многократном включении заголовочного файла #ifndef __SOME_HEADER_H__ #define __SOME_HEADER_H__ // тело файла #endif #ifndef __SOME_HEADER_H__ #define __SOME_HEADER_H__ // тело файла #endif file.h #include file.h file.cpp

Примеры File1.cpp File2.cpp int a ; // внешняя линковка, используется в file1.cpp extern int c ; // ошибка (с не определена) int d ; // ошибка (d определена дважды) double eight ; // ошибка – внешнее имя из file1.cpp static int bar = 7 ; // все хорошо – внутренняя комп. int sum (int a, int b) // функция с внешней компоновкой { return a + b ; } void foo () {}; // функция с внешней компоновкой int a ; // внешняя линковка, используется в file1.cpp extern int c ; // ошибка (с не определена) int d ; // ошибка (d определена дважды) double eight ; // ошибка – внешнее имя из file1.cpp static int bar = 7 ; // все хорошо – внутренняя комп. int sum (int a, int b) // функция с внешней компоновкой { return a + b ; } void foo () {}; // функция с внешней компоновкой int sum(int, int); // объявление ф-ции и другой единицы extern int a ; // внешняя a (из file2.cpp) extern int c ; // ошибка (с не определена) int d ; // ошибка (d определена дважды) int eight () { return sum(3,5); } // Ok void bar () { foo(); } // Ошибка: foo не определена int sum(int, int); // объявление ф-ции и другой единицы extern int a ; // внешняя a (из file2.cpp) extern int c ; // ошибка (с не определена) int d ; // ошибка (d определена дважды) int eight () { return sum(3,5); } // Ok void bar () { foo(); } // Ошибка: foo не определена