Ремонт принтеров, сканнеров, факсов и остальной офисной техники


назад Оглавление вперед




[4]

4 Управление размещением переменных

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

Для эффективного размещения и доступа к переменным компилятору необходимо сообщить дополнительную информацию. К такой информации информации относятся следующие сведения:

•будет ли переменная изменятся программно (константы);

•будет ли переменная изменяться помимо программы (порты и прочие регистры специального назначения);

•должна ли переменная обнулиться (инициализироваться) при перезапуске или запуске программы;

•в каком банке памяти должна размещаться переменная.

В соответствии с этими дополнительными данными осуществляется в том числе и оптимизация окончательного кода.

PIC C компилятор поддерживает такие стандартные квалификаторы, как const и volatile. Квалификатор типа const указывает на неизменность объекта. Любая попытка изменить содержимое переменной, помеченной квалификатором const, приведет к выдаче компилятором соответствующего сообщения. Все объекты, помеченные пользователем как const размещаются в специальной секции, которая называется "строка в ПЗУ". Все такие объекты должны инициализироваться при описании, так как в дальнейшем их значений не может быть изменено. Пример: const int version = 3;

Квалификатор volatile сообщает компилятору, что нельзя гарантировать сохранность (неизменность) значения этой переменной между двумя удачными обращениями к ней из программы. Имеются в виду служебные регистры, значение которых может меняться помимо программы. Это предотвращает удаление "лишних" ссылок на этот объект на этапе оптимизации кода, что, в данном случае, может изменить поведение программы. Кроме всего, этим квалификатором надо помечать и те переменные, которые изменяются процедурами обработки прерываний. Пример:

[[volatile unsigned char PA @ 0x05;

К таким объектам организуется процедура доступа отличная от обычной. Например, если вы в программе присвоете обычной переменной занчение 1, то переменная будет очищена и инкрементирована, та же операция с переменной, отмеченной как volatile, произведет запись единицы в рабочий регистр с последующим переносом значения из рабочего регистра в память.

4.2 Специальные квалификаторы типов

Контроллерная ориентация компилятора требует наличия дополнительных (специальных) квалификаторов. К таким квалификаторам относятся: persistent, bank1, bank2, bank3. Если использована опция компилятора -STRICT, то эти квалификаторы надо записывать в виде:

persistent, bank1, bank2, bank3. Эти квалификаторы могут применяться и к

указателям, но они несовместимы с переменными класса auto. Если вы хотите их использовать для переменных локальных по отношению к функции, то необходимо добавить ключевое слово static. Пример:

void func (void)

persistent int intvar1; Неправильно (класс auto)!!! static persistent int intvar2; Правильно

Тело функции.


4.3 Указатели

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

Рассмотрим особенности реализации указателей для контроллеров среднего класса:

•Указатели на ОЗУ

Поскольку 8-ми битный указатель может адресовать только 256 байт, то они могут дать доступ только к 0-й и 1-й страницам ОЗУ.

•Указатели на 2-ю и 3-ю страницы ОЗУ

Для доступа к верхним страницам ОЗУ необходимо использовать соответствующие модификаторы (Bank2, Bank3). Заметьте, что для микроконтроллеров этого класса невозможно определить указатель на ОЗУ, который бы давал доступ к более чем двум страницам или парам страниц, отличных от указанных выше.

•Константные указатели

Константные указатели - 16-ти битные и могут давать доступ как к ОЗУ так и к ПЗУ. Если старший разряд указателя равен нулю, что адресуется ОЗУ, иначе - ПЗУ. Такие указатели могут использоваться только для чтения данных, независимо от типа адресуемой памяти (ОЗУ или ПЗУ). Другими словами, осуществлять запись в ОЗУ с помощь. Константного указателя нельзя, что собственно следует из его определения. Но польза от них, тем не менее, очень существенная. Особенно удобно их использовать в функциях, связанных с обработкой строк. Передавая в функцию константный указатель на строку, вам не надо беспокоиться о ее местоположении (ОЗУ или ПЗУ). В любом случае доступ будет прозрачен.

•Указатели на функции

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

Чтобы четче определить поведение и особенности указателя и объекта на который он указывает можно комбинировать различные квалификаторы. К наиболее часто употребимым квалификаторам относятся const, volatile, persistent. Применяя комбинации этих квалификаторов необходимо следить за соответствием (отсутствием противоречий) квалификаторов, оказывающих воздействие на свойства собственно указателя и объекта на котрый он указывает. Правила, которые помогут сделать все правильно, просты: если квалификатор находится слева от "*" в описании указателя, то он воздействует на объект, адресуемый указателем. Если квалификатор находится справа, то он воздействует на собственно указатель. Проиллюстрируем это примерами: [[volatile char * nptr;

По умолчанию любая переменная, если она не была явно инициализирована, обнуляется. Это не противоречит стандарту языка С. Однако, бывают случаи, когда данные сохраняются после рестарта или даже цикла включения-выключения. Чтобы исключить очистку переменной при старте программы нужно воспользоваться квалификатором persistent. Все переменные помеченные таким образом размещаются отдельно. Существует несколько библиотечных функций, которые позволяют проверять и инициализировать такие переменные.

Квалификаторы bankl, ... - используются для размещения переменных в указанной странице памяти. Они неприменимы для указателей в микроконтроллерах начального класса.

Не существует квалификатора bank0, так как переменные по умолчанию, в том числе аргументы функций и объекты auto, размещаются в нулевой странице. Примеры:

static bank3 unsigned char Masha; bank3 unsigned char * ptrMasha;

static bank3 unsigned char * bank2 ptrMasha2; Собственно указатель будет размещен во второй странице.


объявляет указатель на volatile символ. Другими словами в этом примере квалификатор воздействует на объект, адресуемый указателем nptr.

[[char * volatile ptr;

так как квалификатор располагается справа от "*", то он будет воздействовать на собственно указатель ptr, а не на объект. И заключительный пример по этому поводу:

[[volatile char * volatile nnptr;

теперь будет описан volatile указатель на volatile переменную.

Рассмотрим некоторые аспекты применения константных указателей. Они применяются для косвенного обращения к переменным описанным как const. В общем их поведение (константных указателей) не отличается от поведения обычных указателей, но компилятор препятствует выполнению операций записи с использованием этих указателей. Вот несколько примеров: [[const char * cptr;

при этом выражение:

[[char ch = *cptr;

абсолютно легально, в то время как выражение: *cptr = ch;

недопустимо и вызовет ошибку.



[стр.Начало] [стр.1] [стр.2] [стр.3] [стр.4] [стр.5] [стр.6] [стр.7]