Скачать презентацию
Идет загрузка презентации. Пожалуйста, подождите
Презентация была опубликована 11 лет назад пользователемПавел Тимушкин
1 Лекция 7 Модульность
2 Причины модульности Структурированность Данные, разделенные по отдельным файлам проще поддаются структурированию, анализу и навигации Абстракция и сокрытие реализации Возможность использования функций без указания их реализации Возможность создания библиотек Частичная компиляция Наличие «промежуточного формата» и этапа «связывания» позволяет проводить компиляцию только части проекта
3 Последовательность сборки Препроцессирование Обработка включаемых файлов и директив компилятора Подготовка «чистого» кода Компиляция Синтаксическая и семантическая обработка Трансляция реализаций в машинные коды Компоновка Связывание имен и реализаций Подготовка конечного исполнимого файла Исходный код *.c,*.h, *.cpp,*.hpp Единица трансляции *.i Единица трансляции *.i Промежуточный файл *.obj Исполнимый файл *.exe, *.dll, *.lib Препроцессирование Компиляция Компоновка
4 Препроцессор + Компилятор (Compiler) Фактическая схема file1.cpp common.h file1.h file3.h file2.h file2.cpp file3.cpp file1.obj file2.obj file3.obj Компоновщик (Linker) file.exe
5 Препроцессирование
6 Этапы препроцессирования Начальное процессирование Подготовка текста программы к разбору Лексический разбор (токенизация) Разбиение текста программы на лексические единицы (лексемы или токены) – ключевые слова, имена, операторы. Подстановка Включение заголовочных файлов, условная компиляция, раскрытие макросов
7 Начальное процессирование Чтение файла в память Файл прочитывается как последовательность байт Разбиение на строки Последовательность байт разбивается на последовательность строк. Разделителями являются принятые в ОС символы (CR,LF,CR LF) Подстановка триграфов и диграфов Тройные символы типа ??/ заменяются на \ Склеивание «разбитых» строк Строка, заканчивающаяся символом \, присоединяет к себе следующую строку Замена комментариев на пробелы Однострочные комментарии от // до конца строки Многострочные комментарии от /* до первого появления */
8 Скрытые ловушки Склеивание комментариев Вложенные комментарии 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 ; } */
9 Лексический разбор (токенизация) Разделение по whitespace Whitespace (пробельными) символами являются символы пробела, табуляции и переноса строки «Жадный» разбор в неоднозначных случаях В неоднозначных случаях выбирается допустимая лексема максимальной длины. Например a+++b будет разобрано как a ++ + b Сообщение об ошибке, если лексема не принадлежит языку Например, в случае ` и т.п. a a b b
10 Макроподстановка Включение заголовочных файлов Директивы (команды) комилятору Подстановка макросов Условная компиляция #include#if#ifdef #pragma#else #ifndef #define#elif #undef#endif #error #include#if#ifdef #pragma#else #ifndef #define#elif #undef#endif #error
11 Включение заголовочных файлов Полное включение Директива #include полностью замещается текстом включаемого файла в текущей единице трансляции. Поиск стандартных заголовочных файлов Заголовочный файл ищется среди списка каталогов стандартных библиотек путем добавления к ним пути в угловых скобках. Поиск локальных заголовочных файлов Аналогично предыдущему, но в начало поиска добавлюятся каталоги с файлом, в котором указана директива, а также «каталоги дополнительного включения». #include #include "file.h"
12 Специальные директивы Директива генерации ошибки Генерация ошибки с текстовым сообщением. Используется при условной компиляции (например, чтобы сообщить о неподдерживаемых компиляторе или платформе). Директива компилятора Специфична для каждого компилятора. Используется для управления поведением компилятора. #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" )
13 Макросы Непараметризованный макрос Указывает препроцессору, что в дальнейшем коде следует заменять лексему name на соответствующий текст text. Параметризованный макрос Указывает препроцессору, что в дальнейшем коде следует заменять последовательность лексем name(параметры) на текст text, в котором лексемы-параметры заменяются аргументы макроса Отмена макроса Отменяет дальнейшую подстановку имени #undef name #define name text #define name(x,y) x+y
14 Примеры #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 ); \ }
15 Макрооператоры # и ## Преобразование в строку Параметр шаблона преобразуется в строку (заключается в кавычки) Конкатенация лексем Две лексемы-имени, между которыми находится символ ##, соединяются в одну #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
16 Недостатки макросов Отсутствие типизации Досинтаксическая подстановка #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);
17 Условная компиляция #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
18 Условная компиляция #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
19 Компиляция
20 Этапы компиляции Синтаксический анализ Выделение инструкций, проверка их синтаксиса Семантический анализ Разрешение имен, соответствие типов, приоритет операций и т.п. Трансляция в машинный код Перевод содержимого функций единицы трансляции в машинные коды с сохранением имен и прототипов. Все исользуемые имена на этом этапе должны быть объявлены, но могут не быть определены. Результатом компиляции является промежуточный («объектный») файл, содержащий откомпилированный код и таблицу имен всех объектов, доступных в этой единице трансляции. Код может содержать символические ссылки на неразрешенные имена (определенные, например, в других единицах трансляции).
21 Компоновка
22 Этапы компоновки Разрешение имен Поиск соответствий имен в разных единицах трансляции. На этом этапе все имена должны быть разрешены Связывание Подстановка адресов соответствующих объектов (переменных, функций) вместо символических имен. Сборка Подготовка финального исполнимого файла (добавление заголовка, связывание с точкой входа, связывание с runtime-функциями и т.п.)
23 Внутренняя и внешняя компоновка Внешняя компоновка Имя, которое может быть использовано в других единицах трансляции, считается именем со внешней компоновкой Ко внешним данным относятся: Глобальные переменные (объявленные вне функций) Функции Глобальные пользовательские типы Все остальное – внутренние данные 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 ; }
24 Ключевое слово 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); // необязательно
25 Ключевое слово 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); // прототип функции с внутренней // компоновкой
26 Правило одного определения 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
27 Примеры 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 не определена
Еще похожие презентации в нашем архиве:
© 2024 MyShared Inc.
All rights reserved.