- •I справочный материал ц
- •Подразумевается, что читатель знаком с показательной формой записи действи- етльных чисел.
- •Int a[5]; // массив a[] из 5-и элементов типа int
- •Int a1, a2, a3, a4, a5; // 5 отдельных переменных типа int
- •Void boot_program_page (uint32_t page, uint8_t *buf){
- •Int main(void){
- •Isr_noblock
- •Isr_naked
- •Isr_alias()
- •Isr_aliasof()
- •Isr_block
Escape-последовательность
Код символа
Наименование
символа
\a
0x07
Звуковой сигнал
\b
0x08
«Забой» (возврат
на символ)
\f
0x0c
Перевод страницы
\n
0x0a
Перевод строки
\r
0x0d
Возврат каретки
\t
0x09
Горизонтальная
табуляция
\v
0x0b
Вертикальная
табуляция
\\
0x5c
Обратная черта
0x27
Апостроф
\"
0x22
Кавычки
\?
0x3f
Знак вопроса
\000
000
Любой восьмеричный
код символа
\0x00
0x00
Любой
шестнадцатеричный код символа
Escape-последовательности
ведут свое начало с тех времен, когда
работа велась через консольные текстовые
терминалы - эти последовательности
управляли положением «курсора» на
терминале или печатающем устройстве.
Подразумевается, что читатель знаком с показательной формой записи действи- етльных чисел.
При вводе символов по их кодам в escape-последовательнос- ти следует помнить, что код не может быть больше 255 (в десятичном представлении).
Наконец, строковая константа - это последовательность символов, заключенная в кавычки. Среди символов строковой константы могут быть и escape-последовательности. Если введены подряд несколько строковых констант, разделенных лишь пробелами, табуляциями, переводами строки или комментариями - они объединяются в одну строковую константу. Длинные строки можно переносить со строки на строку при помощи символа переноса - той же самой «обратной черты».
Есть несколько особенностей слияния и переноса строк, связанных с обработкой пробелов:
Если происходит слияние строк - результирующая строка будет содержать последовательно все символы обеих строк (это очевидно).
Если строка переносится при помощи символа переноса, то в результирующую строку будет включены все пробелы от последнего символа до символа переноса и все пробелы от начала следующей строки до константы.
Вот примеры, поясняющие сказанное:
"простая строковая константа" "слияние строк " "123"
"перенос строки \
123"
"еще один вариант\
переноса строки"
Компилятор преобразует эти константы
в следующие:
"вариант\
переноса"
"простая
строковая константа"
"слияние
строк 123"
"перенос
строки 123"
"еще
один вариант
переноса
строки"
"вариантпереноса"
Важной особенностью строковых констант заключается в том, что компилятор всегда добавляет к явно введенным программистом символам еще один - символ завершения строки, код которого 0х00 (так называемый null-символ или завершающий ноль). Этот символ никак не виден в тексте программы, но обрабатывается компилятором и программой.
Переменные
В процессе работы любая программа не только использует константы, т.е. фиксированные значения, но и получает, изменяет и выводит данные различных типов, т.е. оперирует изменяющимися числами (как было сказано ранее, все данные, в конце концов, есть числа).
Изменяемые величины хранятся в ОЗУ, каждое отдельное число в отдельных ячейках. Для обозначения таких ячеек введена особая лексема - переменная.
Переменная - это идентификатор, обозначающий строго определенную область памяти, содержащую данные конкретного типа. Для определения любых переменных не допускается использовать идентификаторы, совпадающие с ключевыми словами языка или уже определенными ранее (например, введенных программистом типов).
Из определения переменной следует ее неразрывная связь с одним из определенных типов, т.е. переменные могут быть типа char, int, float и т.д. В программе каждая переменная должна быть обязательно определена, т.е. описана. Описание переменной осуществляется по следующему шаблону7:
<тип> <список идентификаторов>;
Здесь тип - это один из ранее определенных типов, а список идентификаторов - это один или более идентификаторов, разделенных запятыми. Завершать определение должна традиционная точка с запятой. Запятая - это особый разделитель, используемый для разделения элементов списка, т.е. таких элементов, которые должны восприниматься компилятором как некая неделимая группа.
unsigned long var; int a, b, c; char ch;
Пример демонстрирует определение переменной var, имеющей тип «беззнаковое длинное целое», трех переменных a, b и с типа «целое число со знаком» и одну переменную ch типа «символ».
Встретив определение переменных, компилятор резервирует необходимое количество ячеек памяти, которые затем будут использованы в программе по усмотрению программиста. Использование неописанных переменных в программе не допускается. По умолчанию каждой из описанных переменных сразу присваивается нулевое значение - говорят «переменная проинициализирована значением по умолчанию» (инициализация по умолчанию характерна не для всех переменных, о чем будет сказано далее). Далее будет показано, как можно инициализировать переменные другими значениями.
Программист должен знать, что память для хранения переменных выделяется в порядке их описания, т.е. для вышеприведенного примера в ОЗУ сразу после 4-го байта переменной var будут следовать 2 байта переменной a и т.д. Порядок байтов, составляющих переменную, определяется платформой, для которой компилируется программа. Для микроконтроллеров AVR принято, что многобайтные переменные хранятся в памяти «от младшего байта к старшему», т.е. первым размещается младший байт (наименее значащие биты числа), а затем все более старшие, вплоть до последнего (наиболее значащие биты числа).
При описании переменных могут дополнительно использоваться ключевые слова static, register, extern и volatile. Эти слова могут располагаться как до определения типа переменной, так и после него, однако обязательно до указания идентификатора. Если переменная объявлена с использованием слова register, это означает, что компилятор поместит ее в один из доступных регистров микроконтроллера. Не стоит надеяться, что регистровые переменные каким-то образом помогут создать более быстродействующую программу: для большинства случаев результат будет скорее обратный, хотя в некоторых случаях положительный эффект может быть.
Ключевое слово volatile - очень важное. Дословно оно означает «изменяемая», что на первый взгляд излишне для переменной, само наименование которой означает изменение значения. Однако, дело тут в другом. Компилятор в процессе своей работы анализирует написанный программистом текст программы и старается убрать из него те части, которые явно не несут никакого смысла (подробнее об этом см. в главе «Об оптимизаторе программ»). В частности, компилятор может исключить все участки программы, которые обрабатывают переменные, не изменяющие (с точки зрения компилятора) значения. Разумеется, далеко не всегда это соответствует замыслам программиста. Ключевое слово volatile, использованное при объявлении переменной, укажет компилятору, что эта переменная все-таки изменяется, пусть даже и неизвестным компилятору способом. Можно считать, что volatile есть синоним слова «неприкосновенный», т.е. объявленную таким образом переменную нельзя трогать при оптимизации.
Назначение остальных ключевых слов будет рассмотрено далее.
Массивы
Массив - это последовательно хранимый набор нескольких «пронумерованных» переменных одинакового типа, называемых элементами массива.
Для определения массива используется следующий шаблон:
<тип> <идентификатор>[<размер>];
Здесь тип - как и ранее, любой из определенных типов, обозначающий тип каждого элемента массива, идентификатор - это собственно имя переменной-массива, а размер (который может и отсутствовать) - это константа, ограничивающая количество элементов массива.
Обратите внимание на то, что квадратные скобки должны присутствовать всегда, независимо от того, задается ли размер или нет - это признак массива.
Из определения массива следует, что, во-первых, все элементы массива находятся в памяти друг за другом, а во-вторых, имеют одинаковый тип. Чем же это отличается от обычного последовательного определения нескольких однотипных переменных?
