Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015

Тут можно читать онлайн Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - бесплатно полную версию книги (целиком) без сокращений. Жанр: Прочая старинная литература, издательство Вильямс, год 0101. Здесь Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте лучшей интернет библиотеки ЛибКинг или прочесть краткое содержание (суть), предисловие и аннотацию. Так же сможете купить и скачать торрент в электронном формате fb2, найти и слушать аудиокнигу на русском языке или узнать сколько частей в серии и всего страниц в публикации. Читателям доступно смотреть обложку, картинки, описание и отзывы (комментарии) о произведении.

Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание

Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - описание и краткое содержание, автор Стивен Прата, читайте бесплатно онлайн на сайте электронной библиотеки LibKing.Ru

Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)

Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать книгу онлайн бесплатно, автор Стивен Прата
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

/* file1.с -- определение нескольких глобальных констант */ const double PI = 3.14159; const char * MONTHS [12] =

{"Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль",

"Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"];

/* file2.c -- использование констант, определенных где-то в другом месте */ extern const double PI; extern const * MONTHS]];

Второй подход предполагает помещение констант во включаемый файл. Здесь придется предпринять дополнительное действие, связанное с применением статического внешнего класса хранения:

/* constant.h -- определение нескольких глобальных констант */ static const double PI = 3.14159; static const char * MONTHS [12] =

{"Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль",

"Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь");

/* file1.с -- использование констант, определенных где-то в другом месте */ #include "constant.h"

/* file2.c -- использование констант, определенных где-то в другом месте */ #include "constant.h"

Если вы не укажете ключевое слово static, то включение заголовочного файла constant.h в file1.с и file2.c приведет к тому, что каждый файл будет иметь определяющее объявление того же самого идентификатора, что стандартом ANSI не поддерживается. (Тем не менее, некоторые компиляторы разрешают это.) Делая идентификатор внешним и статическим, вы фактически предоставляете каждому файлу о-г дельную копию данных. Такой прием не будет работать, если по замыслу файлы должны использовать эти данные для связи друг с другом, потому что каждый файл будет видеть только свою копию данных. Однако поскольку данные являются константными (из-за наличия ключевого слова const) и идентичными (т.к. оба файла включают тот же самый заголовочный файл), проблемы не возникают.

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

Квалификатор типа volatile

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

Синтаксис этого квалификатора подобен синтаксису const:

volatile int loci; /* loci является изменчивой ячейкой */ volatile int * ploc; /* ploc указывает на изменчивую ячейку */

520 Глава 12

Эти операторы объявляют loci как значение volatile и ploc как указатель на значение volatile.

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

vail = х;

/* код, в котором х не используется */

val2 = х;

Интеллектуальный (оптимизирующий) компилятор может заметить, что объект х используется два раза без изменения в промежутке его значения. Он временно может сохранить значение х в регистре. Затем, когда х понадобится для val2, появляется возможность сэкономить время, прочитав значение из регистра, а не из исходной ячейки памяти. Такая процедура называется кешированием. Обычно кеширование является полезной оптимизацией, но не в случае, когда значение х изменяется в промежутке между двумя операторами каким-то другим действием. Без ключевого слова volatile у компилятора нет никаких средств, чтобы выяснить, может ли это случиться. Следовательно, во избежание ошибки компилятор не мог реализовать кеширование. Так было до выхода стандарта ANSI. Однако теперь, если в объявлении отсутствует ключевое слово volatile, компилятор может предположить, что значение не изменяется между двумя его применениями, и попытаться оптимизировать данный код.

Значение может быть одновременно и const, и volatile. Например, значение аппаратных часов обычно не должно изменяться программой, что делает его const, но может быть изменено внешним действием, поэтому оно является volatile. Просто поместите оба квалификатора в объявление, как показано ниже; порядок их следования роли не играет:

volatile const int loc;

const volatile int * ploc;

Квалификатор типа restrict

Ключевое слово restrict расширяет вычислительную поддержку, выдавая компилятору разрешение на оптимизацию определенных разновидностей кода. Оно может быть применено только к указателям и сообщает о том, что тот или иной указатель представляет собой единственное первичное средство доступа к объекту данных. Чтобы понять, почему это полезно, необходимо рассмотреть несколько примеров. Взгляните на показанные ниже объявления:

int ar[10];

int * restrict restar = (int *) malloc(10 * sizeof(int));

int * par = ar;

Здесь указатель restar является единственным первичным средством доступа в память, выделенную malloc(). Следовательно, он может быть квалифицирован с помощью ключевого слова restrict. Однако указатель par не является ни первичным, ни единственным средством доступа к данным в массиве ar, поэтому он не может быть квалифицирован как restrict.

Теперь рассмотрим несколько искусственный пример, в котором n имеет тип int:

for (n = 0; n < 10; n++)

{

par[n] += 5; restar[n] += 5;

Классы хранения, связывание и управление памятью 521

ar[n] *= 2; рar[n] += 3; restar[n] + = 3;

}

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

restar[n] += 8; /* корректная замена */

Однако сведение в один двух операторов, в которых участвует par, вызывает вычислительную ошибку:

par[n] += 8; / * дает неправильный ответ */

Причина получения неправильного ответа связана с тем, что внутри цикла ar используется для изменения значения данных между двумя случаями доступа к тем же данным с помощью par.

Без ключевого слова restrict компилятор должен рассчитывать на худший случай, а именно — на то, что какой-то другой идентификатор мог изменить данные между двумя применениями указателя. При наличии restrict компилятор получает свободу в поиске вычислительных сокращений.

Ключевое слово restrict можно использовать в качестве квалификатора для параметров функции, которые являются указателями. Это значит, что компилятор может предположить, что внутри тела функции данные, указываемые такими параметрами, не модифицируются с помощью других идентификаторов, и есть возможность попробовать оптимизации, которые иначе бы не предпринимались. Например, библиотека С содержит две функции для копирования байтов из одного места в другое. В стандарте С99 они имеют следующие прототипы:

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать


Стивен Прата читать все книги автора по порядку

Стивен Прата - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки LibKing.




Язык программирования C. Лекции и упражнения (6-е изд.) 2015 отзывы


Отзывы читателей о книге Язык программирования C. Лекции и упражнения (6-е изд.) 2015, автор: Стивен Прата. Читайте комментарии и мнения людей о произведении.


Понравилась книга? Поделитесь впечатлениями - оставьте Ваш отзыв или расскажите друзьям

Напишите свой комментарий
x