Transcript
Page 1: C++ осень 2013 лекция 1

Углубленное программирование

на языке C++

Алексей Петров

Page 2: C++ осень 2013 лекция 1

Обзор курса. Модуль 1

2

• Лекция 1. Цели и задачи курса. Язык C11. Основы организации и

использования оперативной и сверхоперативной памяти в программах на языке C

• Практикум 1. Адресная арифметика. Одномерные массивы и строки. Алгоритмы их обработки

• Лекция 2. Дополнительные вопросы организации и использования оперативной и сверхоперативной памяти в программах на языке C

• Практикум 2. Многомерные массивы и прочие составные типы языка C. Алгоритмы их обработки. Взаимодействие с ОС

Модуль 1. Углубленное программирование на языке C. Управление памятью

Page 3: C++ осень 2013 лекция 1

Обзор курса. Модуль 2

3

• Лекция 3. Специальные вопросы инкапсуляции

• Лекция 4. Специальные вопросы наследования и полиморфизма. Множественное и виртуальное наследование. Динамическая идентификация типов (RTTI)

• Практикум 3. Проектирование полиморфной иерархии классов повышенного уровня сложности

• Лекция 5. Шаблоны классов и методов. Обработка исключительных ситуаций. Обобщенное и безопасное программирование

• Практикум 4. Разработка и обеспечение безопасности полиморфной

иерархии с шаблонами классов

Модуль 2. Объектная модель языка С++. Безопасное программирование

Page 4: C++ осень 2013 лекция 1

Обзор курса. Модуль 3

4

• Лекция 6. Практическое введение в STL. Функциональное программирование

в C++11 • Лекция 7. Практическое введение в Boost • Практикум 5. Оптимизация полиморфной иерархии классов с использованием

элементов библиотек STL и Boost

Модуль 3. Библиотеки для промышленной разработки ПО: STL, Boost

Page 5: C++ осень 2013 лекция 1

Обзор курса. Модуль 4

5

• Лекция 8. Принципы и шаблоны объектно-ориентированного проектирования.

Базовые шаблоны, шаблоны GoF • Практикум 6. Оптимизация полиморфной иерархии классов с использованием

шаблонов объектно-ориентированного проектирования однопоточных приложений

• Лекция 9. Идиоматика C++. Основы рефакторинга и качество исходного кода. Стандарты кодирования и методологии разработки ПО

• Практикум 7. Рефакторинг и документирование объектно-ориентированного исходного кода

Модуль 4. Шаблоны объектно-ориентированного проектирования. Основы промышленной разработки ПО

Page 6: C++ осень 2013 лекция 1

6

1. Язык C в современной промышленной разработке. Новое в языке C11.

2. Основы препроцессорной обработки. 3. Вопросы управления памятью и

производительность кода. 4. Физическая и логическая

организация оперативной и сверхоперативной памяти.

5. Классы памяти в языке C. 6. Указатели и арифметика

указателей. Одномерные массивы и строки.

7. Постановка индивидуальных задач к практикуму 1.

Лекция 1. Цели и задачи курса. Язык C11. Основы использования памяти в программах на языке C

Page 7: C++ осень 2013 лекция 1

Цель и структура курса

7

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

Состав курса — 9 лекций, 7 практикумов.

Для сравнения: весна 2013 — 10 лекций, 6 практикумов; осень 2012 — 12 лекций, 4 практикума.

Общая аудиторная нагрузка — 64 акад. часа: лекционные занятия — 36 акад. часов; практические работы — 28 акад. часа.

Page 8: C++ осень 2013 лекция 1

Чему научимся? Практический результат (1 / 2)

Обязательно: моделировать систему при помощи UML-диаграмм классов;

разрабатывать код на языке C / C++;

создавать качественный код в структурной и объектно-ориентированной парадигме;

использовать приемы обобщенного и безопасного программирования;

применять промышленные библиотеки STL, Boost;

внедрять в продукт классические архитектурные шаблоны GoF;

оценивать качество и выполнять рефакторинг исходного программного кода;

презентовать и защищать свои разработки перед аудиторией.

8

Page 9: C++ осень 2013 лекция 1

Чему научимся? Практический результат (2 / 2)

По желанию: моделировать варианты использования продукта;

выполнять кодогенерацию по UML-моделям;

использовать новые возможности языка C++11;

писать многопоточные приложения;

создавать POSIX-совместимый переносимый исходный код;

реализовывать графический интерфейс пользователя в Qt.

9

Page 10: C++ осень 2013 лекция 1

Организационные положения

10

Расписание занятий: постановка задач к практикумам — на лекциях 1, 2, 3, 4, 6, 8 и 9

(работа выполняется индивидуально и в парах!).

Регламент занятия: продолжительность — 4 акад. часа с 1 или 2 перерывами общей

продолжительностью до 10 минут;

вопросы — общезначимые: в любое время (во время пауз или по поднятию руки!), индивидуальные: в перерыве или после занятия;

ведение профессиональной видеосъемки (задавайте вопросы по существу и разборчиво!).

Знакомство с аудиторией: известные языки программирования (C, C++, Java);

опыт разработки, известные среды и технологии.

Page 11: C++ осень 2013 лекция 1

Рекомендуемая литература (1 / 5)

11

Гамма Э., Хелм Р., Джонсон Р., Влиссидес Дж. Приемы объектно-ориентированного проектирования. Паттерны проектирования. — Питер, 2007. — 366 с.

Дейтел Х., Дейтел П. Как программировать на C++. — Бином-Пресс, 2009. — 800 с.

Дьюхэрст С. Скользкие места С++. Как избежать проблем при проектировании и компиляции ваших программ. — ДМК Пресс, 2012. — 264 с.

Кериевски Дж. Рефакторинг с использованием шаблонов. — Вильямс, 2006. — 400 с.

Керниган Б., Ритчи Д. Язык программирования C. — Вильямс, 2012. — 304 с.

Коплиен Дж. Программирование на C++. — Питер, 2005. — 480 с.

Page 12: C++ осень 2013 лекция 1

Рекомендуемая литература (2 / 5)

12

Липпман С., Лажойе Ж. Язык программирования C++. Вводный курс. — Невский Диалект, ДМК Пресс. — 1104 с.

Липпман С., Лажойе Ж., Му Б. Язык программирования C++. Вводный курс. — Вильямс, 2007. — 4-е изд. — 896 с.

Лишнер Р. STL. Карманный справочник. — Питер, 2005. — 188 с.

Макконнелл С. Совершенный код. Мастер-класс. — Русская редакция, 2012. — 896 с.

Мейерс С. Наиболее эффективное использование C++. 35 новых рекомендаций по улучшению ваших программ и проектов. — ДМК Пресс, 2012. — 298 с.

Мейерс С. Эффективное использование C++. 55 верных советов улучшить структуру и код ваших программ. — ДМК Пресс, 2006. — 300 с.

Page 13: C++ осень 2013 лекция 1

Рекомендуемая литература (3 / 5)

13

Мюссер Д., Дердж Ж., Сейни А. C++ и STL. Справочное руководство. — Вильямс, 2010. — 432 с.

Прата С. Язык программирования C. Лекции и упражнения. — Вильямс, 2013. — 960 с.

Прата С. Язык программирования C++. Лекции и упражнения. — Вильямс, 2012. — 6-е изд. — 1248 с.: ил.

Саммерфилд М. Qt. Профессиональное программирование. Разработка кроссплатформенных приложений на C++. — Символ-Плюс, 2011. — 560 с.

Саттер Г. Новые сложные задачи на C++. — Вильямс, 2005. — 272 с.

Саттер Г. Решение сложных задач на C++. — Вильямс, 2008. — 400 с.

Саттер Г., Александреску А. Стандарты программирования на C++. — Вильямс, 2008. — 224 с.

Седжвик Р. Алгоритмы на C++. — Вильямс, 2011. — 1056 с.

Page 14: C++ осень 2013 лекция 1

Рекомендуемая литература (4 / 5)

14

Страуструп Б. Программирование. Принципы и практика использования C++. — Вильямс, 2011. — 1248 с.

Страуструп Б. Язык программирования C++. — Бином, 2011. — 1136 с.

Фаулер М. Рефакторинг. Улучшение существующего кода. — Символ-Плюс, 2008. — 432 с.

Шилдт Г. C++: базовый курс. — Вильямс, 2008. — 624 с.

Шилдт Г. C++. Методики программирования Шилдта. — Вильямс, 2009. — 480 с.

Шилдт Г. Полный справочник по C. — Вильямс, 2009. — 704 с.

Шилдт Г. Полный справочник по C++. — Вильямс, 2007. — 800 с.

Шлее М. Qt 4.8. Профессиональное программирование на C++. — БХВ-Петербург, 2012. — 894 с.

Page 15: C++ осень 2013 лекция 1

Рекомендуемая литература (5 / 5)

15

Abrahams, D., Gurtovoy, A. C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond (Addison Wesley Professional, 2004).

Demming, R., Duffy, D.J. Introduction to the Boost C++ Libraries; Volume I – Foundations (Datasim Education BV, 2010).

Demming, R., Duffy, D.J. Introduction to the Boost C++ Libraries; Volume II – Advanced Libraries (Datasim Education BV, 2012).

Drepper, U. What Every Programmer Should Know About Memory (2007). URL: http://people.redhat.com/drepper/cpumemory.pdf.

King K. C Programming: A Modern Approach, 2nd ed. (W. W. Norton & Co., 2008).

Meyers, S. CPU Caches and Why You Care. URL: http://aristeia.com/TalkNotes/PDXCodeCamp2010.pdf

Musser, D.R., Saini, A. STL Tutorial and Reference Guide: C++ Programming with the Standard Template Library (Addison-Wesley, 1995).

Page 16: C++ осень 2013 лекция 1

Web-ресурсы и онлайн-книги

Официальный Web-сайт проекта Boost: http://www.boost.org/.

Официальный Web-сайт проекта Eclipse: http://www.eclipse.org/.

Справка по языкам C / C++: http://ru.cppreference.com/w/, http://en.cppreference.com/w/.

C Programming: http://en.wikibooks.org/wiki/C_Programming.

Google C++ Style Guide: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml

More C++ Idioms: http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms.

Schäling, B. The Boost C++ Libraries: http://en.highscore.de/cpp/boost/.

16

Page 17: C++ осень 2013 лекция 1

Блог дисциплины

Размещен по адресу: http://tp.mail.ru/blog/cpp/

Что делать: подписаться на обновления;

изучить более ранние записи;

задавать вопросы;

участвовать в опросах и обсуждениях.

17

Page 18: C++ осень 2013 лекция 1

Язык C в современной промышленной разработке

Разработанный в начале 1970-х гг. язык C по-прежнему активно используется в практике программирования: ядра операционных систем: Linux, Windows NT, z/OS;

инструментальные средства: gdb, vi / vim, gedit;

системы управления БД: MySQL, Oracle Database;

Web-серверы: Apache, nginx;

проекты Mail.Ru Group: ICQ, tarantool и пр.

Особый интерес представляет применение С в *nix-проектах с высокой нагрузкой или высокой доступностью.

18

Page 19: C++ осень 2013 лекция 1

Основы препроцессорной обработки

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

Директивы препроцессора: обычно имеют первым символом # («решетку»); распространяют свое действие от точки вхождения до конца файла.

Типичными директивами препроцессора являются: #include — включает в текст файлы с исходным кодом; #define — вводит в исходный код символические константы и

макроопределения (обратная директива — #undef); #if, #ifdef, #ifndef, #else, #elif, #endif — реализуют условное включение

фрагментов исходного кода в текст, передаваемый компилятору; #error — возбуждает ошибку времени компиляции; #pragma — осуществляет действие, определяемое реализацией

компилятора.

19

Page 20: C++ осень 2013 лекция 1

Основы препроцессорной обработки: пример использования #define

20

#define SIZE 100

#define PRINT_X printf("X:\t%7d\n", &x)

#define CUBE(N) (N) * (N) * (N)

int a[SIZE];

// эквивалентно: int a[100];

PRINT_X;

// эквивалентно: printf("X:\t%7d\n", &x);

printf("%d\n", CUBE(SIZE));

// эквивалентно:

// printf("%d\n", 100 * 100 * 100);

Page 21: C++ осень 2013 лекция 1

Основы препроцессорной обработки: пример условной компиляции и #error

21

// выбор генератора псевдослучайных чисел

#ifdef ANSI_C_LIKE

#define A 1103515245

#define C 12345

#else

#define A 22695477

#define C 1

#endif

// выброс ошибки, если компилятор не является компилятором C++

#ifndef __cplusplus

#error A C++ compiler is required!

#endif

Page 22: C++ осень 2013 лекция 1

Вопросы управления памятью и производительность кода: зачем?

Неоптимальная работа с памятью становится ограничивающим фактором для большинства программ.

Проблему усугубляет рост сложности подсистемы памяти, в частности — механизмов кэширования и пр.

22

Page 23: C++ осень 2013 лекция 1

Модели управления памятью и области видимости объектов данных

Предлагаемые языком C модели управления объектами данных (переменными) закреплены в понятии класса памяти, которое охватывает: время жизни — продолжительность хранения объекта в памяти; область видимости — части исходного кода программы, из которых

можно получить доступ к объекту по идентификатору; связывание — части исходного кода, способные обращаться к объекту

по его имени.

Для языка C характерны три области видимости: блок — фрагмент кода, ограниченный фигурными скобками (напр.

составной оператор), либо заголовок функции, либо заголовок оператора for, while, do while и if;

прототип функции; файл.

23

Page 24: C++ осень 2013 лекция 1

Связывание объектов данных

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

Для объектов, видимых в пределах файла (глобальных), язык предлагает два варианта связывания: внутреннее — объект является «приватным» для файла и может

использоваться лишь в нем (но любой функцией!);

внешнее — объект может использоваться в любой точке многофайловой программы.

24

Page 25: C++ осень 2013 лекция 1

Связывание объектов данных: пример

25

// область видимости: прототип функции

int foo(double *d, int n);

// область видимости: блок

for(int i = 0; i < n; i++)

int bar;

// ...

// область видимости: файл, внутреннее связывание

static int count = 0;

// область видимости: файл, внешнее связывание

double accuracy = 0.001;

Page 26: C++ осень 2013 лекция 1

Время жизни объектов данных

Объекты данных в программах на языке С имеют статическую или автоматическую продолжительность хранения: время жизни статических объектов тождественно времени выполнения

программы;

время жизни автоматических объектов в целом тождественно времени выполнения охватывающего их блока.

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

Автоматическими является большинство объектов, видимых в пределах блока.

26

Page 27: C++ осень 2013 лекция 1

Инициализация объектов данных

Статические объекты неявно инициализируются нулем (0, '\0‘), автоматические объекты неявно не инициализируются вообще.

Для явной инициализации статических объектов должны использоваться константные выражения, вычислимые компилятором.

Например:

char space = 0x20; // верно

size_t int_sz = sizeof(int); // верно

size_t int10_sz = 10 * int_sz; // неверно

27

Page 28: C++ осень 2013 лекция 1

Классы памяти в языке C

28

Класс памяти Время жизни Область видимости

Тип связывания

Точка определения

Автоматический Автоматическое Блок Отсутствует В пределах блока, опционально auto

Регистровый Автоматическое Блок Отсутствует В пределах блока, register

Статический, без связывания

Статическое Блок Отсутствует В пределах блока, static

Статические, с внешним связыванием

Статическое Файл Внешнее Вне функций

Статические, с внутренним связыванием

Статическое Файл Внутреннее Вне функций, static

Page 29: C++ осень 2013 лекция 1

Автоматические и регистровые переменные: пример

29

// автоматические переменные int foo(unsigned u) auto int bar = 42; // ... // регистровые переменные int get_total(register int n) // ... for(register int i = 0; i < n; i++) // ...

Page 30: C++ осень 2013 лекция 1

Размещение объектов данных на регистрах процессора

Применение ключевого слова register для активно используемых переменных: несет все риски «ручной оптимизации» кода и полезно преимущественно

для встроенных систем и аппаратных архитектур, не имеющих компиляторов C с долгой историей (gcc разрабатывается с 1987 г.);

относится к регистрам ЦП (в x86/x86-64: AX, EBX, RCX и т.д.), но не кэш-памяти ЦП 1-го или 2-го уровня;

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

вполне может игнорироваться компилятором, который будет действовать «на свое усмотрение» (например, разместит переменную на регистре, потребность в котором возникнет позднее всего).

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

30

Page 31: C++ осень 2013 лекция 1

Статические объекты с внутренним связыванием и без связывания: пример

31

// без связывания: // статические внутренние объекты функций int callee(int n) static int counter = 0; // не часть функции! // … // с внутренним связыванием: // статические внутренние объекты файлов static double epsilon = 0.001; int foo(double accuracy) if(accuracy < epsilon) // ...

Page 32: C++ осень 2013 лекция 1

Статические объекты с внешним связыванием: пример

32

// с внешним связыванием: // статические внешние объекты ("внешняя память") double time; // внешнее определение long int fib[100]; // внешнее определение extern char space; // внешнее описание // (объект определен в другом файле) int main(void) extern double time; // необязательное описание extern long int fib[]; // необязательное описание;; // размер массива необязателен // ...

Page 33: C++ осень 2013 лекция 1

Классы памяти функций

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

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

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

Например: int one(void); // внешнее определение // статическое определение static int two(void); // необязательное внешнее описание extern int three(void);

33

Page 34: C++ осень 2013 лекция 1

Операция sizeof и тип size_t

Унарная операция sizeof: допускает скобочную и бесскобочную (только для переменных) нотацию:

sizeof a или sizeof(T);

возвращает объем памяти, выделенной под объект простого или составного типа, в байтах как значение переносимого типа size_t, являющегося псевдонимом одного из базовых беззнаковых целых типов (ср. int32_t и пр.).

не учитывает возможного выравнивания объекта.

Использование вычисляемых компилятором конструкций вида sizeof(T) не влияет на производительность кода, но повышает переносимость.

34

Page 35: C++ осень 2013 лекция 1

Указатели и арифметика указателей. Тип ptrdiff_t

Стандартные указатели типа T* как составной тип языка C и символический способ использования адресов можно условно считать «шестым классом памяти», важной особенностью которого является поддержка специфической арифметики.

Пусть p, p2 — указатели типа T*, а n — значение целого типа (желательно — ptrdiff_t). Тогда: p + n либо n + p — адрес, смещенный относительно p на n единиц

хранения размера sizeof(T) в направлении увеличения адресов («вправо»);

p – n — адрес, смещенный относительно p на n единиц хранения размера sizeof(T) в направлении уменьшения адресов («влево»);

p++ либо ++p, p-- либо --p — аналогичны p + 1 и p – 1, соответственно; p – p2 — разность содержащихся в указателях адресов, выраженная в

единицах хранения и имеющая тип ptrdiff_t. Разность положительна при условии, что p расположен в пространстве адресов «правее» p2.

35

Page 36: C++ осень 2013 лекция 1

Одномерные массивы (строки)

Для одномерного массива T a[N] в языке C справедливо: массивы поддерживают полную и частичную инициализацию, в том числе

с помощью выделенных инициализаторов; в частично инициализированных массивах опущенные значения

трактуются как нули; элементы массивов размещаются в памяти непрерывно и занимают

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

строки char c[N] конструктивно являются частными случаями массивов, при этом в корректных строках c[sizeof(c) – 1] == ‘\0‘;

sizeof(a) возвращает размер массива в байтах (не элементах!); sizeof(a[0]) возвращает размер элемента в байтах.

Принятая система обозначения массивов является лишь особым способом применения указателей.

36

Page 37: C++ осень 2013 лекция 1

Одномерные массивы (строки): пример

37

// с освобождением круглых скобок int a[] = 1, 2, 3; // эквивалентно int a[3] = 1, 2, 3; // с частичной неявной инициализацией int b[5] = 1, 2, 3; // эквивалентно: // int b[5] = 1, 2, 3, 0, 0; // с выделенными инициализаторами int c[7] = 1, [5] = 10, 20, [1] = 2; // эквивалентно: // int c[7] = 1, 2, 0, 0, 0, 10, 20;

Page 38: C++ осень 2013 лекция 1

Одномерные массивы (строки) и указатели

Пусть T a[N] — массив. Тогда: имя массива является константным указателем на 0-й элемент:

a == &a[0];

для любых типов и длин массивов справедливо: &a[i] == a + i и a[i] == *(a + i);

С учетом этого эквивалентны прототипы: int foo(double [], int);

int foo(double *, int);

Передать массив в функцию можно так, как показано выше, или как пару указателей: на 0-й и N-й элементы (обращение к элементу a[N] без его разыменования допустимо): int foo(double *, double *);

38

Page 39: C++ осень 2013 лекция 1

Макроопределение NULL

Стандартное макроопределение NULL расширяется препроцессором до константы с семантикой «пустого» указателя, который… является константным целочисленным выражением, вычисляемым в

длинный или короткий нуль (0L или 0), либо

выступает как результат приведения такого значения к void* (напр. (void*)0).

Значение NULL приводимо к любому типу-указателю и может использоваться в конструкциях вида: if (p != NULL) // ...

if (q == NULL) // ...

39

Page 40: C++ осень 2013 лекция 1

Вопросы безопасного программирования

Инициализировать указатели во время определения: допустимый адрес;

0, (void*)0 или NULL.

Проверять: значения указателей перед их разыменованием;

значения индексов элементов массивов перед использованием;

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

40

Page 41: C++ осень 2013 лекция 1

Стандартные функции ввода-вывода

Имя функции

Назначение функции Причины ошибок

POSIX-совместима?

int scanf(const char *restrict format, ... );

scanf Осуществляет форматный ввод с консоли — чтение из стандартного входного потока stdin. Возвращает количество успешно считанных элементов ввода

Некорректная входная послед-сть (EILSEQ) Недостаточно аргументов (EINVAL)

Да

int printf(const char *restrict format, ...);

printf Осуществляет форматный вывод в консоль — запись в стандартный выходной поток stdout. Возвращает количество переданных в поток байт

EILSEQ, EINVAL и др.

Да

41

Page 42: C++ осень 2013 лекция 1

Стандартные функции для работы с динамической памятью (1 / 2)

Имя функции

Назначение функции Причины ошибок

POSIX-совместима?

void *malloc(size_t size);

malloc Выделяет неиспользуемый участок памяти объекту данных размера size байт, не меняя содержимое указанного участка

Недостаточно памяти (ENOMEM)

Да

void *calloc(size_t nelem, size_t elsize);

calloc Выделяет неиспользуемый участок памяти массиву из nelem элементов размера elsize байт каждый и выполняет его поразрядное обнуление

Недостаточно памяти (ENOMEM)

Да

42

Page 43: C++ осень 2013 лекция 1

Стандартные функции для работы с динамической памятью (2 / 2)

Имя функции

Назначение функции Причины ошибок

POSIX-совместима?

void *realloc(void *ptr, size_t size);

realloc Изменяет размер объекта данных, на который указывает ptr, до size. Если указатель ptr пуст, вызов эквивалентен malloc. Если size == 0, память под объектом освобождается

Недостаточно памяти (ENOMEM)

Да

void free(void *ptr);

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

Нет Да

43

Page 44: C++ осень 2013 лекция 1

Выравнивание объектов, размещаемых статически. GCC-атрибут aligned (1 / 2)

44

Одним из способов повышения производительности программы на языке «среднего уровня» является такое размещение данных в ОЗУ, при котором они эффективно загружаются в кэш-память ЦП. Для этого данные должны быть, как минимум, выровнены на границу линии кэш-памяти данных 1-го уровня (L1d).

Выравнивание объекта данных в ОЗУ обычно определяется характеристиками выравнивания, которые имеет соответствующий тип данных. При этом: выравнивание скалярного объекта определяется собственные

характеристикой выравнивания приписанного ему базового типа; выравнивание массива, — если размер каждого элемента не кратен

величине выравнивания, — распространяет свое действие только на элемент с индексом 0;

выравнивание объектов в программе на языке C может регулироваться на уровне отдельных переменных и типов данных., для чего в компиляторе GCC служит атрибут aligned.

Page 45: C++ осень 2013 лекция 1

Выравнивание объектов, размещаемых статически. GCC-атрибут aligned (2 / 2)

45

Выравнивание статически размещаемых переменных имеет силу как для глобальных, так и для автоматических переменных. При этом характеристика выравнивания, присущая типу объекта, полностью игнорируется.

При выравнивании массивов гарантированно выравнивается только начальный, нулевой элемент массива.

Page 46: C++ осень 2013 лекция 1

Выравнивание объектов, размещаемых статически. Атрибут aligned: пример

46

// выравнивание, регулируемое на уровне объекта

// переменная qwd выравнивается на границу 64 байт

uint64_t qwd __attribute((aligned(64)));

// выравнивание, регулируемое на уровне типа

// переменные типа al128int_t (синоним int)

// выравниваются на границу 128 байт

typedef int __attribute((aligned(128))) al128int_t;

al128int_t aln;

Page 47: C++ осень 2013 лекция 1

Выравнивание объектов, размещаемых динамически. Функция posix_memalign

47

Функция posix_memalign: определена в стандарте POSIX 1003.1d; имеет прототип

int posix_memalign(void **memptr, size_t alignment, size_t size); выделяет неиспользуемый участок памяти размера size байт,

выровненный на границу alignment, и возвращает указатель на него в memptr;

допускает освобождение выделенной памяти функцией free().

Требования к значению alignment: кратно sizeof(void*); является целочисленной степенью числа 2.

Ошибки (EINVAL, ENOMEM): значение alignment не является кратной sizeof(void*) степенью 2; недостаточно памяти.

Page 48: C++ осень 2013 лекция 1

posix_memalign: пример (1 / 2)

48

int b[7] = 1, [5] = 10, 20, [1] = 2; // массив-источник

int *p = NULL, // массив-приемник

errflag; // код ошибки posix_memalign

// установить размер линии кэш-памяти данных 1-го уровня

// (L1d); типичное значение: 64 байта

long l1dcls = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);

// проверить, удался ли вызов sysconf()

if (l1dcls == -1)

// если вызов sysconf() неудачен, использовать значение

// выравнивания по умолчанию

l1dcls = sizeof(void*);

Page 49: C++ осень 2013 лекция 1

posix_memalign: пример (2 / 2)

49

// выделить память с выравниванием на границу строки L1d

errflag = posix_memalign((void**)&p, l1dcls, sizeof b);

if(!errflag)// в случае успеха posix_memalign возвращает 0

printf("\nL1d cache line size is %ld\n", l1dcls);

printf("p and &p are %p and %p\n", p, &p);

p = memcpy(p, b, sizeof(b));

// ...

free(p);

else

printf("posix_memalign error: %d\n", errflag);

Page 50: C++ осень 2013 лекция 1

Практикум 1

50

Постановка задачи

Решить индивидуальные задачи 1 и 2 в соответствии с формальными требованиями.

Для этого в блоге дисциплины: узнать номер индивидуального варианта;

узнать постановку задач.

Page 51: C++ осень 2013 лекция 1

Спасибо за внимание

Алексей Петров