Зарезервированные ключевые слова



Министерство образования и науки Российской Федерации

Государственное образовательное учреждение

высшего профессионального образования

 

«САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ

МОРСКОЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ»

 

 

Е. В. Коротицкий, Ю. Е. Коротицкая

 

Основы языка СИ для микроконтроллеров AVR

Учебное пособие

 

Санкт-Петербург

2011

Основы языка Си для микроконтроллеров AVR

Универсальный язык С был разработан как инструмент для написания операционной среды UNIX.

Язык С поддерживает процедурно-ориентированную парадигму программирования, т.е. парадигма – взаимосвязанный набор процедур.

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

Препроцессор языка C и его команды

Препроцессор (макропроцессор) — это составная часть языка Си, которая обрабатывает исходный текст программы до того, как он пройдет через компилятор. Препроцессор читает строки текста и выполняет действия, определяемые командными строками. Если первым символом в строке, отличным от пробела, является символ #, то такая строка рассматривается препроцессором как командная. Командные строки называются директивами препроцессора.

Препроцессор компилятора CodeVisionAVR имеет несколько директив. В табл. 1 даётся их краткое описание.

Табл. 1 –Директивы препроцессора компилятора CodeVisionAVR

Директива Назначение
#include Используется для включения в программу другого файла
#define Используется для замены одних лексических единиц языка Си на другие, а также для генерации макросов
#undef Используется для отмены действия директивы #define
#if

Используются для условной компиляции

Sifdef
#ifndef
#else
#endif
#line Используется для изменения встроенных макросов _LINE_и_FILE_
#error Позволяет остановить компиляцию и отобразить сообщение об ошибках
#asm Используются для включения в исходную программу ассемблерного кода
#pragma Разрешает специальные директивы компилятора

ВСЕ директивы препроцессора начинаются со знака #. После директив препроцессора точка с запятой НЕ СТАВИТСЯ.

Директива #include

Пример:

Директива #includeимеет две синтаксические формы:

#include "имя_файла" и #include <имя_файла>

Имя_файласостоит из имени файла.

 

Директива #includeшироко используется для включения в программу так называемых заголовочных файлов (файлы с расширением .h),содержащих определения периферийных устройств и векторов прерываний используемого микроконтроллера, прототипы библиотечных функций, прототипы функций, определённых пользователем, и т. д.

#include "имя_файла.h"

Директивы #define, #undef

Директива #defineслужит для замены часто использующихся одних лексических единиц языка Си (констант, ключевых слов, операторов или выражений) на другие, так называемые идентификаторы. Идентификаторы, заменяющие текстовые или числовые константы, называют именованными константами. Идентификаторы, заменяющие фрагменты программ, называют макроопределениями, причём макроопределения могут иметь аргументы.

Директива #defineимеет две синтаксические формы:

#define идентификатор текст

#define идентификатор (список параметров) текст

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

Пример:

#define А 15 #define В (А+20) // Эти директивы заменят в тексте программы

каждый идентификатор А на число 15, а каждый идентификатор В на выражение (15+20) вместе с окружающими его скобками.

Пример:

#define X(a,b,c) ((а)*(b)-(с)) // Препроцессор в соответствии с этой директивой заменит фрагмент Y=X(k+m,k-m,n); на фрагмент

Y=((k+m)*(k-m)-(n))

Директивы #if, #ifdef, #ifndef, #else и #endif

Директивы #if, #ifdef, #ifadef, #elseи #endifможно использовать для условной компиляции. Условные конструкции препроцессора позволяют компилировать или пропускать часть программы в зависимости от выполнения некоторого условия. Условие может принимать одну из описываемых ниже форм:

#if константное_выражение // Проверяется значение выражения, составленного

из констант, и, если оно не равно нулю, компилируется (включается) последующий текст.

#ifdef идентификатор // Последующий текст компилируется, если «идентификатор» уже был определён для препроцессора директивой #define.

#ifndef идентификатор // Последующий текст компилируется, если «идентификатор» в данный момент не определён.

 

За любой из трёх условных команд может следовать произвольное число строк текста, содержащих, возможно, команду вида #elseи заканчивающихся #endif.Еcли проверяемое условие справедливо, то строки между #elseи #endifигнорируются. Если же проверяемое условие не выполняется, то игнорируются все строки между проверкой и командой #else,а если её нет, то командой #endif.

Пример:

#if А=15 [группа операторов 1] // Если выражение А = 15 истинно, то будет

 #else [группа операторов 2] // компилирована группа операторов 1,

#endif // в противном случае будет компилирована группа операторов 2.

Встроенные макросы

В CodeVisionAVR есть встроенные макросы. В табл. 2 перечислены эти макросы и дано их краткое описание.

Табл. 2 – Встроенные макросы компилятора CodeVisionAVR

Макрос Описание
_СН1Р_АТХХХХХ_ ATXXXXX — выбранный тип чипа
_CODEVISIONAVR_ Версия компилятора
_DATE_ Текущая дата в формате ттт ddyyyy
_FILE_ Текущий скомпилированный файл
_LINE_ Текущий номер строки скомпилированного файла
_MCU_CLOCK_ FREQUENCY_ Заданная тактовая частота чипа AVR
_MODEL_SMALL_ Модель памяти SMALL
_MODEL_TINY_ Модель памяти TINY
_OPTIMIZE_SIZE_ Оптимизация по размеру
_OPTIMIZE_SPEED_ Оптимизация по скорости
_TIME_ Текущее время в формате hh:mm:ss
_UNSIGNED_CHAR_ Символ (char) по умолчанию беззнаковый
_8BIT_ENUMS_ 8-битовые перечисления

 

Макрос _СН1Р_АТХХХХХ_

Макрос _СН1Р_АТХХХХХ_ будет определён, если АТХХХХХ, записанный буквами верхнего регистра, совпадает с типом чипа, определённым в опции Chip (Чип) при конфигурировании проекта (см. Закладка С Compiler (Компилятор Си)).

Этот макрос можно использовать для условной компиляции.

Пример:

#ifdef _CHIP_AT90S8535_ [группа операторов 1] // Если при конфигурировании проекта выбран чип типа AT90S8535, то будет определён макрос _CHIP_AT90S8535_ и компилирована группа операторов 1.

#else

ttifdef _CHIP_AT90S8515_ [группа операторов 2]// Если при конфигурировании проекта выбран чип типа AT90S8515, то будет определён макрос _CHIP_AT90S8515_ и компилирована группа операторов 2.

#endif [группа операторов 3] ttendif // Если при конфигурировании проекта выбран чип, отличный от AT90S8535 и AT90S8515, то оба макроса не будут определены и будет компилирована группа операторов 3.

 

Макрос _CODEVISIONAVR_

Этот макрос представляет собой номер версии компилятора. Он представляется как целое (integer); например, для VI.24. lx Standart он будет равен 1241.

Пример:

int Y=_CODEVISIONAVR_; // В этой версии компилятора переменной Y // присваивается значение 1241

 

Макрос _DATE_

Этот макрос представляет собой текущую дату компиляции файла. Он представляется как строка символов в формате ттт dd уууу, где ттт — месяц (три первые буквы), dd — день, уууу — год. Например: 12 июля 2004 года будет пред­ставлено как Jul 12 2004.

Пример:

char string[]=_DATE_; // Присваиваем строке string!] значение

// "mmm dd уууу", где mmm dd уууу текущая // дата компиляции файла

 

Макрос_FILE_

Этот макрос представляет собой название скомпилированного файла. Он представляется как строка символов.

Пример:

char string!]=_FILE_; // Присваиваем строке string[] значение // ""file_name.c", где file_name.c имя // скомпилированного файла

 

Макрос _LINE_

Этот макрос представляет собой текущий номер строки скомпилированного файла. Он представляется как целое (integer).

Пример:

В этом примере в левом столбце приведены номера строк:

11: int Y=0;    // Объявляем и сразу инициализируем переменную Y.

12: Y=_LINE_; // Присваиваем переменной Y значение макроса _LINE_, который здесь равен 12 (номер текущей строки).

 

Макрос _MCU_CLOCK_FREQUENCY_

Этот макрос представляет собой значение тактовой частоты чипа AVR, которая определена в опции Clock (Тактовая частота) при конфигурировании проекта. Значение выражается в герцах. Макрос представляется как целое (integer).

Пример:

/* При заданной тактовой частоте 4 МГц переменная Q будет иметь значение 4000000 */

long int Q; // Объявляем переменную Q

Q =_MCU_CLOCK_FREQUENCY_; // Присваиваем переменной Q значение макроса _MCU_CLOCK_FREQUENCY_

 

Макросы _MODEL_TINY_ и _MODEL_SMALL_

В зависимости от того, какая модель памяти выбрана в опции Memory Model (Модель памяти) при конфигурировании проект,будет определён соответствующий макрос.

Если выбрана модель памяти Tiny, то будет определён макрос _MODEL_TINY_.

Если выбрана модель памяти Small, то будет определён макрос _MODEL_SMALL_.

Эти макросы можно использовать для условной компиляции.

Пример:

#ifdef _M0DEL_TINY_ [группа операторов 1] // Если при конфигурировании // проекта выбран тип памяти Tiny, то выражение #ifdef будет истинным и будет компилирована группа операторов 1.

#else[группа операторов 2] // Если при конфигурировании проекта выбран тип памяти Small, то будет компилирована группа операторов 2.

#endif

 

Макросы _OPTIMIZE_SIZE_ и _OPTIMIZE_SPEED_

В зависимости от того, какой способ оптимизации выбран в опции Optimize for (Оптимизировать по) при конфигурировании проекта, будет определён соответствующий макрос.

Если выбрана оптимизация по размеру, то будет определён макрос _OPTIMIZE_SIZE_.

Если выбрана оптимизация по скорости выполнения, то будет определён макрос _OPTIMIZE_SPEED_.

Эти макросы можно использовать для условной компиляции.

Директива #line

Директиву #lineможно использовать, чтобы изменить встроенные макросы

_LINE_и_FILE_ (см. 1.1.4 Встроенные макросы).

Синтаксис:

#1iпе целая_константа ["имя_файла"]

Пример:

/* Установим встроенный макрос _LINE_ в 25, а _FILE_ в "test.с" */

#line 25 "test.с"

/* Установим встроенный макрос _LINE_ в 36 */

#line 36

Директива #error

Директиву terrorможно использовать, чтобы остановить компиляцию и отобразить сообщение об ошибках.

Синтаксис:

#error сообщение;

Пример:

#error Здесь ошибка! // В этом месте компиляция будет остановлена и будет выдано сообщение: "Здесь ошибка!"

Директивы #asm и #endasm

Директивы #asm и #endasm можно использовать для включения в любом месте исходной программы ассемблерного кода.

Директива #asm говорит компилятору о начале ассемблерного кода, а директива #endasm — о его завершении.

Пример:

/* Вставка ассемблерного кода */

void main(void)

{

#asm              // начало ассемблерного кода

sei ;                // разрешаем глобальные прерывания

#endasm        // окончание ассемблерного кода

}

Зарезервированные ключевые слова

Следующий список ключевых слов зарезервирован компилятором. Эти слова НЕ МОГУТ использоваться как имена идентификаторов.

 

break flash eeprom sfrw
bit float else static
case for enum struct
char funcusd extern switch
const goto register typedef
continue if return union
default inline short unsigned
defined int signed void
do interrupt sizeof volatile
double long sfrb while

Идентификаторы

Идентификатором является имя, которое даётся переменной, функции, метке или другому объекту. Идентификатор может содержать буквы латинского алфавита (A...Z, a...z) и цифры (0...9), а также символ подчеркивания (_), который считается буквой.

ИДЕНТИФИКАТОР может начинаться ТОЛЬКО с буквы или со знака подчеркивания.

При написании идентификатора имеет значение регистр, т. е. Temp, temp и TEMP будут восприниматься компилятором как различные идентификаторы.

Максимальная длина идентификатора не должна превышать 31 символ.

В качестве идентификатора нельзя использовать зарезервированные ключевые слова (см. 1.2. Зарезервированные ключевые слова), а также имена функций библиотеки компилятора.

Комментарии

Комментарий — это набор символов, который компилятором игнорируется. Однако на этот набор символов накладываются следующие ограничения. Внутри набора символов, который представляет комментарий, не может быть специальных символов, определяющих начало (/*) и конец (*/). Комментарии могут занимать как одну строку, так и несколько.

Пример:

/* комментарии к программе */

/* начало алгоритма */

или

/*комментарии можно записать в следующем виде, однако следует быть осторожным, чтобы внутри последовательности, которая компилятором игнорируется, не попались операторы программы, которые также будут игнорироваться */

Константы

Константами называются перечисления величин в программе. В отличие от переменных такие имена нельзя изменять.

В языке Си разделяют четыре типа констант: целые константы, константы с плавающей точкой, символьные константы и строковые литералы.

Целая константа — это десятичное, двоичное, восьмеричное или шестнадцатеричное число, которое представляет целую величину в одной из следующих форм: десятичной, двоичной, восьмеричной или шестнадцатеричной.

Десятичная константа состоит из одной или нескольких десятичных цифр, причём первая цифра не должна быть нулем (в противном случае число будет воспринято как восьмеричное). Например, 9876.

Двоичная константа начинается с обязательной последовательности Obи содержит одну или несколько двоичных цифр (цифры двоичной системы счисления: 0 или 1). Например, Оb 1100.

Восьмеричная константа начинается с обязательного префикса 0и содержит одну или несколько восьмеричных цифр (среди цифр должны отсутствовать восьмерка и девятка, так как эти цифры не входят в восьмеричную систему счис­ления). Например, 0123.

Шестнадцатеричная константа начинается с обязательной последовательности Ох или ОХ и содержит одну или несколько шестнадцатеричных цифр (цифры, представляющие собой набор цифр шеснадцатеричной системы счисления: (0...9,A,B,C,D,E,F). Например, Охеа или ОХЕА.

Константа с плавающей точкой (floating point) — десятичное число, представленное в виде действительной величины с десятичной точкой или экспонентой.

Число с плавающей точкой состоит из целой и дробной части и/или экспоненты. Константы с плавающей точкой представляют положительные величины удвоенной точности (имеют тип double).Для определения отрицательной величины следует сформировать константное выражение, состоящее из знака минуса и положительной константы.

Например: -1.6Е-3, -0.072, -0.16Е5.

Символьная константа (Character) — представляется символом, заключённым в одиночные кавычки. Значением символьной константы является числовой код символа.

Например: 'g'.

Строковая константа (String), или литерал, — последовательность символов (включая строковые и прописные буквы русского и латинского алфавита, а также цифры), заключённых в кавычки («...»).

Например: «Сидоров А.Г.», «город С-Петербург», «АБВГ1234», «» (пустая строка). Строковый литерал имеет тип char[].

Константы могут быть сгруппированы в массивы, которые могут иметь до 8 измерений.

Чтобы определить константы, хранящиеся во FLASH-памяти, следует использовать ключевые слова flashили const.

Чтобы определить константы, хранящиеся в EEPROM, следует использовать ключевое слово eeprom.

Чтобы определить константы, хранящиеся в регистрах, следует использовать ключевое слово register.

Константные выражения автоматически определяются в течение компиляции.

Пример:

/* Эти константы будут расположены в EEPROM */

eeprom intint_constl=12-7; // Целая константа int_constl будет равна 5

eeprom charchar_const='b'; // Символьная константа char_const будет равна числовому коду ASCII символа 'b', т. е. 0x62

/* Эти константы будут расположены во FLASH-памяти */

flash longlong_int_const=136L; // Целая длинная константа

// long_int_const будет равна 136

flash intint_array[10]={9,16}; // Этот целочисленный массив имеет 10 членов, причём первые два это 9 и 16, а остальные нули

const intint_const2=0123; // Целая константа int_const2 будет равна 123 в восьмиричном или 83 в десятичном виде

/* Эта константа будет расположена в регистре */

register intint_const3=0xl0; // Целая константа int_const3 будет равна 16 в десятичном или 10 в // шестнадцатеричном виде

/* Эти константы будут расположены в SRAM */

intint_const4=0bl0; // Целая константа int_const4 будет равна 2 в десятичном или 10 в двоичном виде

charstring_const[]="Hello!"; // Это строковая константа

Переменные

В отличие от констант переменные во время выполнения программы могут множество раз изменять свои значения.

Переменные могут быть глобальнымиили локальными.

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

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

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

[<место хранения>] определение типа> <идентификатор>;

Пример:

/* Объявление глобальных переменных */

longх;

charу;

/* Инициализация глобальных переменных */

Х=10;

/* Объявление с одновременной инициализацией глобальных переменных */

intc=0xfa;

voidmain(void)/* Объявление локальных переменных,

{

int а;

long b;

}

bit<идентификатор>;

Распределение памяти для битовых переменных осуществляется в порядке объявления, начиная с бита 0 регистра R2, затем бит 1 регистра R2 и так далее в порядке возрастания. Максимум можно объявить 104 битовых переменных.

Пример:

/* Битовые переменные */

bitbit_varl=l; // Объявление и инициализация битовой переменной bit_varl, которая будет храниться в бите 0 регистра R2

bitbit_var2; // Объявление битовой переменной bit_var2, которая будет храниться в бите 1 регистра R2

В выражениях битовые переменные автоматически переводятся в unsigned char (беззнаковые символьные).

Массивы

Переменные могут быть сгруппированы в массивы.

Массивы— это группа элементов одинакового типа (double, float, int и т. п.). Из объявления массива компилятор должен получить информацию о типе элементов массива и их количестве.

Синтаксис объявления массивов:

[<модификатор места хранения;>] <тип> идентификатор массива> [<константное_ выражение;>] ;

Компилятор поддерживает многомерные массивы, которые могут иметь вплоть до 8 измерений. Многомерные массивы формализуются списком константных выражений, следующих за идентификатором массива, причём каждое константное выражение заключается в свои квадратные скобки. Каждое константное выражение в квадратных скобках определяет число элементов по данному измерению массива, так что объявление двухмерного массива содержит два константных выражения, трехмерного — три и т. д.

Пример:

intloc_array2[2][2] = {{4,9}, {7,1}}; // Объявление и инициализация целочисленного локального многомерного массива 1ос_аггау2

Типы данных

Все типы данных, поддерживаемые компилятором Си, их размеры и диапазоны их возможных значений приведены в табл. 3.

Табл. 3 – Типы данных компилятора

Тип Размер (Биты) Диапазон
bit (бит) 1 0, 1
char (символ) 8 -128...127
unsigned char (символ без знака) 8 0...255
signed char (символ со знаком) 8 -128...127
int (целое) 16 -32768...32767
short int (короткое целое) 16 -32768...32767
unsigned int (целое без знака) 16 0...65535
signed int (целое со знаком) 16 -32768...32767
long int (длинное целое) 32 2147483648...2147483647
unsigned long int (длинное целое без знака) 32 0...4294967295
signed long int (длинное целое со знаком) 32 -2147483648...2147483647
float (с плавающей точкой) 32 + 1.175е-38.. +3.402е38
double (двойное) 32 ±1.175е-38...±3.402е38

 

Тип данных bit (бит) поддерживается только для глобальных переменных.

Все переменные должны быть описаны до их использования. Описание задаёт тип, за которым следует список одной или более переменной этого типа.

 

Пример:

int a, b; // Объявление переменных а и b как целых

char с; // Объявление переменной с как символьной

Если указано ключевое слово unsigned, т. е. число беззнаковое, то старший бит интерпретируется как часть числа. При отсутствии ключевого слова unsigned переменная считается знаковой.

Пример:

signed char х, а; // Объявление переменных х и а как символьных со знаком

unsigned char у, b; // Объявление переменных у и b как символьных без знака

Операнды и операции

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

Присваивание также является выражением, и значением такого выражения является величина, которая присваивается.

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

Выражения со знаками операций могут участвовать в выражениях как операнды. Выражения со знаками операций могут быть унарными (с одним операндом), бинарными (с двумя операндами) и тернарными (с тремя операндами).

Унарные операции

Унарное выражениесостоит из операнда и предшествующего ему знака унарной операции и имеет следующий формат: знак-унарной-операции операнд.

В табл. 4 перечислены унарные операции компилятора и приведены их знаки.

Табл. 4 – Унарные операции компилятора

Знак операции Операция
$<?>$ арифметическое отрицание (отрицание и дополнение)
~ побитовое логическое отрицание (дополнение)
! логическое отрицание
* разадресация (косвенная адресация)
& вычисление адреса
+ + инкремент
- - декремент
sizeof размер

 

Унарные операции выполняются справа налево.

Операция арифметического отрицания ($<?>$) вырабатывает отрицание своего операнда. Операнд должен быть целым (int) числом или числом с плавающей точкой (float).

Пример:

/* Унарная операция (-) */

int х = 12; // Объявляем и инициализируем целую переменную х

х = -х; // переменной х присваивается её отрицание, т.е. х принимает значение -12

Операция двоичного дополнения (~) вырабатывает двоичное дополнение своего операнда. После этой операции все 1 в двоичном коде значения операнда меняются на 0, а все 0 — на 1.

Пример:

/* Унарная операция (~) */

unsigned char а=0b1001001; // Объявляем и инициализируем беззнаковую символьную переменную а unsigned char b;

     // Объявляем беззнаковую символьную

     // переменную b

b=~a; // С переменной а делаем операцию двоичного

     // дополнения и полученное значение присваиваем

     // переменной Ь. В результате

    // b = 0b00ll0ll0 = 0x36 = 54

 

Операция логического отрицания НЕ (!) вырабатывает значение 0, если операнд есть истина (не ноль), и значение 1, если операнд равен нулю (0).

Пример:

/* Унарная операция (!) */

int х;          // Объявляем целую переменную х

int у=0;    // Объявляем и инициализируем целую переменную у

int z=0x4f; // Объявляем и инициализируем целую переменную z .

х=!у;           // С переменной у делаем операцию логического отрицания и полученное значение присваиваем переменной х. В результате переменная х получит значение, равное 1, так как переменная у имела значение, равное 0 (ложно).

 х= !z; //С переменной z делаем операцию логического отрицания и полученное значение присваиваем переменной х. В результате переменная х получит значение, равное 0, так как переменная z имела значение, не равное 0 (истина).

 

Операция разадресации (*) осуществляет косвенный доступ к адресуемой величине через указатель. Операнд должен быть указателем. Результатом операции является величина, на которую указывает операнд. Результат не определён, если указатель содержит недопустимый адрес.

Операция вычисления адреса (&) даёт адрес своего операнда. Операндом может быть любое именуемое выражение. Результатом операции вычисления адреса является указатель на операнд.

Пример:

/* Унарные операции (*) и (&) */

 

int х; // Объявляем целую переменную x
int у=5; // Объявляем и инициализируем целую переменную у
int *adress;

// Объявляем переменную adress как указатель, на что указывает знак * переменной adress присваивается

adress=&x; // адрес (&) переменной х переменной, находящейся по адресу, содержащемуся в переменной adress,
*adress=y; // присваивается значение переменной у, т. е. 5 , что
// эквивалентно записи х=у; т. е. х=5
adress=&y; // переменной adress присваивается адрес (&) // переменной у
x=*adress;

// переменной х присваивается значение, находящееся по адресу, содержащемуся в переменной adress, т. е. значение переменной у, что эквивалентно записи х = у; т. е. х = 5.

 

Операции инкремента и декремента увеличивают или уменьшают значение операнда на единицу и могут быть записаны как справа, так и слева от операнда. Если знак операции записан перед операндом (префиксная форма) (например, ++х), то изменение операнда происходит до его использования в выражении. Ес­ли знак операции записан после операнда (постфиксная форма) (например, х++), то операнд вначале используется в выражении, а затем происходит его изменение.

Пример:

/* Унарные операции (--) и (++) */

int у,- // Объявляем целую переменную у

int х = 5; // Объявляем и инициализируем целую переменную х

--х; // Переменная х будет уменьшена на 1, х = 4

++х; // Переменная х будет увеличена на 1, х = 5

у = 5 + х++; // Сначала берется текущее х (х = 5), к нему прибавляется значение 5, полученный результат присваивается переменной у. После этого значение х увеличивается на 1. Таким образом, после выполнения этой строки у = 10, х = 6

 

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

sizeof(выражение)

В качестве выражения может быть использован любой идентификатор либо имя типа, заключённое в скобки.

Пример:

/* Унарная операция (sizeof) */

double х; // Объявляем переменную х двойной точности

int у; // Объявляем целую переменную у

y=sizeof(х); // у = 4, т. к. х имеет тип double и занимает в памяти 4 Б

y=sizeof(char); // у=1, т. к. тип char занимает в памяти 1 Б.

Бинарные операции

Бинарное выражениесостоит из двух операндов, разделённых знаком бинарной операции, и имеет следующий формат:

операнд 1 знак-бинарной-операции операнд 2

В отличие от унарных бинарные операции, список которых приведён в табл. 5, выполняются слева направо.

Табл. 5 – Бинарные операции компилятора

Знак операции Операция Знак операции Операция
* Умножение А Побитное исключающее ИЛИ
/ Деление && Логическое И
% Остаток отделения II Логическое ИЛИ
+ Сложение » Последовательное вычисление
- Вычитание   Присваивание
« Сдвиг влево * — Умножение с присваиванием
» Сдвиг вправо /= Деление с присваиванием
> Больше %= Остаток от деления с присваиванием
< Меньше -= Вычитание с присваиванием
<= Меньше или равно += Сложение с присваиванием
>= Больше или равно «= Сдвиг влево с присваиванием
== Равно »= Сдвиг вправо с присваиванием
  Не равно &= Побитное И с присваиванием
& Побитное И 1= Побитное ИЛИ с присваиванием
1 Побитное ИЛИ л= Побитное исключающее ИЛИ с присваиванием

 

Операция умножения (*) выполняет умножение операндов.

Операция деления (/) выполняет деление первого операнда на второй. Если две целые величины не делятся нацело, то результат округляется в сторону нуля.

Операция остаток от деления (%) показывает остаток от деления первого операнда на второй. Операндами этой операции должны быть целые числа.

Пример:

/* Бинарные операции (*), (/) и (%) */

int а=37, b=10;// Объявляем и инициализируем целые переменные а и b

int х, у, z;// Объявляем целые переменные х, у и z

х=а*b;                         // х=370

у=а/b;                           // y=3

 z=a%b;                       // z=7

 

Результатом выполнения операции сложения (+) является сумма двух операндов.

Операция вычитания (-) вычитает второй операнд из первого.

Пример:

/* Бинарные операции (+) и (-) */

int а=37, b=10; // Объявляем и инициализируем целые переменные а и b

int х, у;            // Объявляем целые переменные х и у

х=а+b;             // х=47

У=а-b;             // у=27

 

Операции сдвига осуществляют смещение значения первого операнда влево (<<) или вправо (>>) на количество битов, задаваемое вторым операндом. Оба операнда должны быть целыми величинами. Выполняются обычные арифметические преобразования. При сдвиге влево правые освобождающиеся биты устанавливаются в ноль. При сдвиге вправо метод заполнения освобождающихся левых битов за­висит от типа первого операнда. Если тип unsigned, то свободные левые биты устанавливаются в ноль. В противном случае они заполняются копией знакового бита. Результат операции сдвига не определён, если второй операнд отрицательный.

Пример:

int a=1b101001;       // Объявляем и инициализируем целую переменную а;

int x,y;             // Объявляем целые переменные х и у

x=a<<2;          // сдвигаем значение а на 2 бита влево и полученное

// значение присваиваем переменной х; х=0b10100100

y=a>>1;          // сдвигаем значение а на 1 бит вправо и полученное значение присваиваем переменной у; у=0b10100 Значение переменной а не изменяется! а=0b101001

Обратите внимание, что сдвиг влево соответствует умножению первого операнда на степень числа 2, равную второму операнду, а сдвиг вправо соответствует делению первого операнда на 2 в степени, равной второму операнду.

 

/* Бинарные операции (<<) и (>>) */

int а=С int х,

х=а<<2;

у=>>1;

 

Операции отношения (<, >, <=, >=, = =,!=) служат для сравнения значений двух операндов.

Пример:

/* Бинарная операция {!=) */

if (а!=b)                       // Если значение а не равно значению b,[группа операторов!.] // то выполняется [группа операторов1]

else                             // Иначе, если значение а равно значению b, [группа операторов2] выполняется [группа операторов2]

 

Операция побитного логического И (&) сравнивает каждый бит первого операнда с соответствующим битом второго операнда. Если оба сравниваемых бита единицы, то соответствующий бит результата устанавливается в 1, в противном случае — в 0.

Операция побитного логического ИЛИ (|) сравнивает каждый бит первого операнда с соответствующим битом второго операнда. Если любой (или оба) из сравниваемых битов равен 1, то соответствующий бит результата устанавливается в 1, в противном случае результирующий бит равен 0.

Операция побитного исключающего ИЛИ (^) сравнивает каждый бит первого операнда с соответствующим битом второго операнда. Если один из сравниваемых битов равен 0, а второй бит равен 1, то соответствующий бит результата устанавливается в 1, в противном случае, т. е. когда оба бита равны 1 или 0, соответствующий бит результата устанавливается в 0.

Операция логического И (&&) вырабатывает значение 1, если оба операнда имеют ненулевые значения. Если один из операндов равен 0, то результат также равен 0.

Операция логического ИЛИ (||) выполняет над операндами операцию ИЛИ. Она вырабатывает значение 0, если оба операнда имеют значение 0. Если ка­кой-либо из операндов имеет ненулевое значение, то результат операции равен 1.

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

Операция простого присваивания (=) используется для замены значения левого операнда значением правого операнда. В языке Си присваивание также является выражением, и значением такого выражения является величина, которая присваивается.

Кроме простого присваивания, имеется целая группа операций присваивания (*=, /=, %=, -=, +=, <<=, »=, &=, |= и л=), которые объединяют простое присваивание с одной из бинарных операций. Такие операции называются составными операциями присваивания и имеют вид

(операнд 1) (бинарная операция) = (операнд 2)

Составное присваивание по результату эквивалентно следующему простому присваиванию:

(операнд 1) = (операнд 1) (бинарная операция) (операнд 2)

Пример:

/* Бинарные операции (*=, /=, +=) */

а+ = 3; а/ = b; b* = а;

int а = 5;      // Объявляем и инициализируем целую переменную а

int b = 4; // Объявляем и инициализируем целую переменную b

а+ = 3; // эквивалентно а = а+3, в результате а = 8

а/ = b; // эквивалентно а = а/b, в результате а = 8/4 = 2

b* = а;  // эквивалентно b = b*a, в результате b = 4*2 = 8

 

Операции &=, |=  и ^=  часто называют накладыванием маски, а число, стоящее справа от знака такой операции, называют маской. При накладывании маски изменяются значения лишь определённых битов операнда, стоящего слева.

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

Пример:

/* Бинарные операции &=, I = и ^= как операции накладывания маски */

unsigned char х=Оb00111100;    // Объявляем и инициализируем символьные

unsigned char у=0b00111100;     // (байтовые) переменные х,у и z

unsigned char z=0b00111100;     //

/* Наложим на эти числа маску 0b00001111*/

х&=Оb00001111;

/* При накладывании маски операцией &= в тех битах, где в маске стоит значение 0, биты исходного числа принимают значение 0, независимо от первоначального значения. В тех битах, где в маске стоит значение 1, биты исходного числа не изменяются. Таким образом, в результате х=Оb00001100 */

у|=0b00001111;


Дата добавления: 2018-04-15; просмотров: 917; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!