Основы языка си. Структура программы на языке С

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

Первоначально язык Си задумывался как заменитель Ассемблера для написания операционных систем. Поскольку Си - это язык высокого уровня, не зависящий от конкретной архитектуры, текст операционной системы оказывался легко переносимым с одной платформы на другую. Первой операционной системой, написанной практически целиком на Си , была система Unix. В настоящее время почти все используемые операционные системы написаны на Си . Кроме того, средства программирования, которые операционная система предоставляет разработчикам прикладных программ (так называемый API - Application Program Interface ), - это наборы системных функций на языке Си .

Тем не менее, область применения языка Си не ограничилась разработкой операционных систем. Язык Си оказался очень удобен в программах обработки текстов и изображений, в научных и инженерных расчетах. Объектно-ориентированные языки на основе Си отлично подходят для программирования в оконных средах.

В данном разделе будут приведены лишь основные понятия языка Си (и частично C++). Это не заменяет чтения полного учебника по Си или C++, например, книг и .

Мы будем использовать компилятор C++ вместо Cи. Дело в том, что язык Си почти целиком входит в C++, т.е. нормальная программа , написанная на Си , является корректной C++ программой. Слово "нормальная" означает, что она не содержит неудачных конструкций, оставшихся от ранних версий Си и не используемых в настоящее время. Компилятор C++ предпочтительнее, чем компилятор Си , т.к. он имеет более строгий контроль ошибок. Кроме того, некоторые конструкции C++, не связанные с объектно-ориентированным программированием, очень удобны и фактически являются улучшением языка Си . Это, прежде всего, комментарии // , возможность описывать локальные переменные в любой точке программы, а не только в начале блока, и также задание констант без использования оператора #define препроцесора. Мы будем использовать эти возможности C++, оставаясь по существу в рамках языка Си .

Структура Си-программы

Любая достаточно большая программа на Си (программисты используют термин проект ) состоит из файлов. Файлы транслируются Си -компилятором независимо друг от друга и затем объединяются программой-построителем задач, в результате чего создается файл с программой, готовой к выполнению. Файлы, содержащие тексты Си -программы, называются исходными .

В языке Си исходные файлы бывают двух типов:

  • заголовочные, или h-файлы;
  • файлы реализации, или Cи-файлы.

Имена заголовочных файлов имеют расширение " .h ". Имена файлов реализации имеют расширения " .c " для языка Си и " .cpp ", " .cxx " или " .cc " для языка C++.

К сожалению, в отличие от языка Си , программисты не сумели договориться о едином расширении имен для файлов, содержащих программы на C++. Мы будем использовать расширение " .h " для заголовочных файлов и расширение " .cpp " для файлов реализации.

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

определяющая целочисленную переменную x , является ошибкой. Вместо этого следует использовать описание

означающее, что переменная x определена где-то в файле реализации (в каком - неизвестно). Слово extern (внешняя) лишь сообщает информацию о внешней переменной, но не определяет эту переменную.

Файлы реализации , или Cи-файлы, содержат тексты функций и определения глобальных переменных. Говоря упрощенно, Си -файлы содержат сами программы, а h-файлы - лишь информацию о программах.

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

Файлы реализации могут подключать описания, содержащиеся в заголовочных файлах. Сами заголовочные файлы также могут использовать другие заголовочные файлы. Заголовочный файл подключается с помощью директивы препроцессора #include . Например, описания стандартных функций ввода-вывода включаются с помощью строки

#include

(stdio - от слов standard input /output). Имя h-файла записывается в угловых скобках, если этот h-

Лекция № 1

Тема: Знакомство с языком C++. Операторы и типы данных

План

3. Переменные и их типы

4. Операторы и математические функции

5. Операторы ввода/вывода на языке С++

6. Пример программы на С++

1. История развития языка программирования С++

Языка C++, объединяющий в себе свойства языка С и объектно–ориентированного программирова­ния, стал один из главных языков программирования в 90–е годы и твердо продолжает оставаться таким в начале XXI века. Язык C++ получил в наследство от языка С такие качества, как эффективность, компакт­ность, быстрота выполнения и переносимость про­грамм. От объектно–ориентированного программи­рования язык C++ получил новую методологию программирования, позволяющую справиться с возрос­шей сложностью современных задач программирования. А такие элементы языка, как улучшенные шаблоны, привносят в язык C++ еще одну новую методологию программирования: обобщенное программирование. Это тройное наследство является для языка C++ одновре­менно и благословением, и проклятием. Оно делают язык очень мощным, но в то же время и сложным; а это означает, что программистам приходится больше изу­чать.

В последние несколько десятилетий компьютерная тех­нология развивалась поразительными темпами. Языки программирования также претерпели значительную эво­люцию. В 70–е годы такие языки программирования, как С и Pascal, помогли войти в эру структурного программи­рования, принесшего порядок в ту область, которая силь­но нуждалась в этом. Язык С предоставил в распоряже­ние программиста инструменты, необходимые для структурного программирования, а также обеспечил со­здание компактных, быстро работающих программ и возможность адресации аппаратных средств, например, возможность управления портами связи и накопителя­ми на магнитных дисках. Эти качества помогли языку С стать господствующим языком программирования в 80–е годы. Вместе с тем в эти годы появилась новая мо­дель программирования:объектно–ориентированное программирование, или ООП, воплощенное в таких язы­ках, как SmallTalk и C++.

Язык С

Сотрудник компании Bell Laboratories Кена Томпсона в 1969 году разработал язик B (би) для создания других программных систем. Однако этот язык был интерпретируемым, что не позволяло создавать на нем независимые исполняемые файлы. Тем не менее этот язык явился предшественником языка С.

В начале 70–х годов Денис Ритчи из компании Bell Laboratories занимался разработкой опе­рационной системы UNIX. Для выполнения этой ра­боты Ритчи нуждался в таком языке программирования, который был бы кратким, а также мог бы обеспечивать эффективное управление аппаратными средствами и создание компактных, быстро работающих программ. Традиционно такие потребности программистов удов­летворял язык ассемблера, который тесно связан с внут­ренним машинным языком компьютера. Однако язык ассемблера – это язык низкого уровня, т.е. он привязан к определенному типу процессора (или компьютера). Поэтому если программу на языке ассемблера необхо­димо перенести на компьютер другого типа, то ее при­ходится переписывать заново на другом языке ассемб­лера.

Операционная система UNIX пред­назначалась дли работы на разнообразных типах компь­ютеров (или платформах). А это предполагало использование языка высокого уровня. Язык высокого уровни ориентирован на решение задач, а не на конкрет­ное аппаратное обеспечение. Специальные программы, которые называются компиляторами, транслируют про­грамму на языке высокого уровня в программу на внут­реннем языке конкретного компьютера. Таким образом, используя отдельный компилятор для каждой платформы, одну и ту же программу на языке высокого уровня можно выполнять на разных платформах. Ритчи нуждал­ся в языке, который бы объединял эффективность и возможность доступа к аппаратным средствам, имеющи­еся у языка низкого уровня, с более общим характером и переносимостью, присущими языку высокого уровня. Поэтому на основе имеющегося языка программирования В Ритчи разработал язык С. Принято считать, что авторами языка являются Ритчи и Томпсон.

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

Язык С++

С развитием объектно–ориентированной технологии возможностей стандартного языка С уже было недостаточно. В результате появился язык С++.

Язык C++, так же как и язык С, является детищем ком­пании Bell Laboratories. Автор Бьярни Страуструп разработал этот язык в начале 80–х годов. По его собственным словам, «язык C++ был спроектирован главным образом так, чтобы мне и моим друзьям не приходилось программировать на ассемблере, С или различных современных языках высокого уровня. Его главная цель состояла в следующем: сделать так, что­бы отдельным программистам было легче и приятнее писать хорошие программы» .

Страуструп создал C++ на основе языка С, так как язык С был кратким, хорошо подходил для системного программи­ровании, был широко доступен и тесно связан с опера­ционной системой UNIX. Объектно–ориентированная часть языка C++ возникла под влиянием языка модели­рования Simula67. Страуструп добавил элементы ООП в язык С, не изменяя при этом существенно сам язык С.

Название C++ происходит от обозначения оператора инкремента ++ в языке С, который добавляет единицу к значению переменной. Название C++ подразумевает, что этот язык является усовершенствованной (++) версией языка С.

Обобщенное программирование

Обобщенное программирование – это еще одна парадигма программирования, поддерживаемая языком C++. Оно имеет общую с ООП цель – упростить повторное ис­пользование кодов программ. Однако, в то время как в ООП основ­ное внимание уделяется данным, в обобщенном про­граммировании упор делается на алгоритмы. И у него другая область применения. ООП – это инструмент дли разработки больших проектов, тогда как обобщенное программирование предоставляет инструменты для вы­полнения задач общего характера, таких как сортиров­ка данных. Термин обобщен­ный означает создание кода программы, независимого от типа данных. В языке C++ имеются данные различных типов – целые числа, числа с дробной частью, симво­лы, строки символов, определяемые пользователем сложные структуры, состоящие из данных нескольких типов. Если, например, требуется сортировать данные различных типов, то обычно для каждого типа создает­ся отдельная функция сортировки. Обобщенное про­граммирование расширяет язык таким образом, что по­зволяет один раз написать функцию для обобщенного (т.е. неопределенного) типа данных и затем использовать ее для разнообразных реальных типов данных. Это обес­печивается с помощью шаблонов языка C++. (начало)

2. Структура программы на С++

Программа C++ строится из отдельных блоков, на­зываемых функциями. Как правило, программа разделя­ется на ряд крупных задач, а затем для выполнения этих задач разрабатываются отдельные функции.

Большинство программ на С++ имеют следующий вид:

раздел подключения заголовочных файлов

заголовок программы (функции)

тело функции

Заголовок программы

Программа C++ состоит из одного или более модулей, называемых функциями. Выполнение программы начи­нается с функции, имеющей имя main(), поэтому в про­грамме обязательно должна присутствовать функция с таким именем. Если в про­грамме нет такой функции, то в нет и законченной программы; компилятор в этом случае указывает, что функция main() не была определена.

Описание такой функции выполняют в разделе заголовка программы и записывают в виде:

Важно учитывать тот факт, что компилятор С++ различает регистр символов. Поэтому, имя функции, набранное в другом регистре (например: Main() или MAIN()), будет распознаваться как неправильное.

Раздел подключения заголовочных файлов

При создании исполняемого кода программ C++, так же как и в случае с программами С, используется пре­процессор. Это программа, которая обрабатывает исход­ный файл перед основной компиляцией. Чтобы вызвать этот препроцессор, не надо делать ниче­го особенного. Он запускается автоматически при ком­пиляции программы.

Каждая программа на С++ вначале имеет директиву вида:

#include

Эта директива приводит к тому, что препроцессор добавляет в программу содержимое файла iostream. Это типичное для препроцессора действие: добавление или изменение текста в исходном коде перед компиляцией.

Директива #include приводит к тому, что содержимое файла iostream пере­дается в компилятор вместе с содержимым исходного файла. В сущности, содержимое файлаiostream заменя­ет в программе строку #include . Исходный файл не изменяется, а объединенный файл, созданный из исходного файла и файла iostream, обрабатывается на следующем этапе компиляции.

Такие файлы, как iostream, называются файлами вклю­чения (поскольку они включаются в другие файлы) или заголовочными файлами (поскольку они включаются в начале файла). Компиляторы C++ поставляются со мно­гими заголовочными файлами, каждый из которых под­держивает отдельное семейство программных средств. Заголовочные файлы в языке С по традиции имеют рас­ширение h, это самый простой способ идентификации типа файла по его имени. Например, заголовочный файл math.hподдерживает различные математические функ­ции языка С++.

Заголовочные файлы находятся в папке Include среды разработки Turbo C++. Если при запуске программы выдается ошибка, указывающая на отсутствие подключаемого заголовочного файла, то в среде Turbo C++ необходимо выполнить настройку. Для этого выполните команду Options – Directories, в поле Include Directoriesвведите..\INCLUDE, а в поле Library Directories введите..\LIB.

Тело функции

Тело функции содержит инструкции для ком­пьютера, т.е. определяет то, что собственно делает фун­кция.

Тело функции имеет следующий вид:

описание переменных;

операторы;

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

Оператор представляет собой инструкцию для компьютера. Чтобы понять исходный код, компилятор должен знать, когда заканчивается один оператор и начи­нается другой. В некоторых языках программирования используются разделители операторов. В языке Pascal один оператор от следующего отделяется точкой с запятой. В некоторых случаях точку с запятой в языке Pascal можно опускать, например, после оператора перед словом END, когда фактически не происходит разделение двух операторов. Но в языке C++, так же как и в языке С, применяется скорее признак (указатель) конца, чем разделитель. Признак конца – это точка с запятой, которая отмечает конец оператора; она является скорее частью оператора, чем разделителем между операторами. Практический резуль­тат заключается в том, что в языке C++ никогда нельзя опускать точку с запятой.

Инструкция RETURN 0 указывает на завершение работы функции и возврат в вызывающую программу. В главной функции main() эту инструкцию можно не указывать.

В тексте программ допускается использовать комментарии. В языке C++ комментарии обозначаются двойной на­клонной чертой (//). В программах C+ + можно использовать комментарии из языка С, которые заключены между символами /* и */.

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

Последнее обновление: 18.05.2017

Программа на языке Си состоит из набора директив препроцессора, определений функций и глобальных объектов. Директивы препроцессора управляют преобразованием текста до его компиляции. Глобальные объекты определяют используемые данные или состояние программы. А функции определяют поведение или действия программы. Простейшая программа на Си, которая была определена в прошлых темах:

#include int main(void) { printf("Hello world! \n"); return 0; }

Инструкции

Простейшим строительным элементом программы на Си являются инструкции (statements). Каждая инструкция выполняет определенное действие. В конце инструкций в языке Си ставится точка с запятой (;). Данный знак указывает компилятору на завершение инструкции. Например:

Printf("Hello world!");

Вызов функции printf, которая выводит на консоль строку "Hello world!" является инструкцией и завершается точкой с запятой.

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

{ printf("Hello world!"); printf("Bye world!"); }

В этом блоке кода две инструкции. Обе инструкции представляют вызов функции printf() и выводят определенную строку на консоль.

Директивы препроцессора

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

Директива include является директивой препроцессора. Кроме данной include есть еще ряд директив препроцессора, например, define.

Каждая директива препроцессора размещается на одной строке. И в отличие от обычных инструкций языка Си, которые завершаются точкой с запятой ; , признаком завершения препроцессорной директивы является перевод на новую строку. Кроме того, директива должна начинаться со знака решетки #.

Непосредственно директива "include" определяет, какие файлы надо включить в данном месте в текст программы. По умолчанию мы можем подключать стандартные файлы из каталога так называемых "заголовочных файлов", которые обычно поставляются вместе со стандартными библиотеками компилятора. И файл "stdio.h" как раз является одним из таких заголовочных файлов.

Вообще сам термин "заголовочный файл" (header file) предполагает включение текста файла именно в начало или заголовок программы. Поэтому заголовочные файлы подключаются, как правило, в начале исходного кода. Кроме того, заголовочный файл должен быть подключен до вызова тех функций, которые он определяет. То есть, к примеру, файл stdio.h хранит определение функции printf, поэтому этот файл необходимо подключить до вызова функции printf.

Но в целом директивы препроцессора необязательно должны быть размещены в начале файла.

При компиляции исходного кода вначале срабатывает препроцессор, который сканирует исходный код на наличие строк, которые начинаются с символа #. Эти строки расцениваются препроцессором как директивы. И на месте этих директив происходит преобразование текста. Например, на месте директивы #include вставляется код из файла stdio.h.

Функция main

Стартовой точкой в любую программу на языке Си является функция main() . Именно с этой функции начинается выполнение приложения. Ее имя main фиксировано и для всех программ на Си всегда одинаково.

Функция также является блоком кода, поэтому ее тело обрамляется фигурными скобками, между которыми идет набор инструкций.

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

#include void main() { printf("Hello world!"); }

#include int main() { printf("Hello world!"); return 0; }

Использование этих определений не было бы ошибкой, и программа также вывела бы строку "Hello world" на консоль. И для большинства компиляторов это было бы нормально.

Далее мы подробнее рассмотрим определение функций, но здесь надо учитывать следующий аспект. Определение функции в виде int main(void) зафиксировано в стандарте языка С11. Компиляторы прежде всего ориентируются на стандарт языка, его спецификацию. Поэтому если мы используем то определение, которое дано в стандарте языка, то больше шанс, что оно будет поддерживаться всеми компиляторами. Хотя опять же повторюсь, в использовании второго варианта или int main() большой ошибки не будет.

Полностью последний стандарт C11 можно посмотреть по

Рис.1 Структура программы на языке Си.

Внутренняя структура программы

Исполняемая программа на Си состоит из 4 частей: область команд, область статических данных, область динамических данных, область стека. см. Рис.2.

1. Область команд содержит машинные команды; инструкции, которые должен выполнить микропроцессор.

2. Область статических данных для хранения переменных, с которыми работает программа;

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

4. Стек используется для временного хранения данных и адресов возврата из функций.


тело функции /*тело функции*/

printf("Hello World!");

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



2-я строка – имя главной функции main () , эта функция не возвращает никаких параметров (об этом буду говорить немного позже). Программа Си всегда имеет функцию main(). С нее начинается выполнение программы.

3-я строка – начало тела функции. {} определяют тело функции (в Паскале - это begin и end)

4-я строка – комментарий, он не компилируется, а только поясняет что делается.

5-я строка – библиотечная функция – печатать на экране, выражение в скобках на этой строке – параметр функции, он всегда берётся в кавычки.

; - это признак оператора Си, это часть оператора, а не разделитель операторов, как в Паскале.

Советы, как сделать программу читаемой:

1) Выбирать осмысленные имена

2) Использовать комментарии

3) Использовать пустые строки для того, чтобы отделить одну часть функции от другой

4) Помещать каждый оператор в другой строке.

БАЗОВЫЕ ЭЛЕМЕНТЫ ЯЗЫКА СИ

Рассмотрим обязательные элементы, с помощью которых должна оформляться программа на Си:

1. Комментарии – используются для документирования программы. Любая программа должна содержать комментарии: какой алгоритм применяется, что делает программа…

Ø 1 способ : /* Текст */ - в любом месте программы.

Как только компилятор встречает /**/, он их пропускает. Компилятор игнорирует /* */, так как он не в состоянии интерпретировать язык, отличающийся от языка Си. То есть, если вы хотите исключить из компиляции какую-то строку, то заключите её в /**/.

Ø 2 способ : если комментарий большой, то используем такой тип

/* Строка 1 - для комментария любой длины

строка 3*/

Ø 3 способ : // - текст до конца строки.

2. Идентификатор - это имя, которое присваивается какому-либо объекту (переменной). Используются строчные и прописные буквы, цифры и знак подчёркивания. Строчные и прописные буквы различаются. (В Бейсике не различаются). Если назвать переменную name, Name или NAME, то это будут разные переменные.

Начинаются идентификаторы с буквы или знака подчеркивания. Например, _name. Но не рекомендуется начинать с _, так как этот знак используется для глобальных имен сомого языка Си.

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

b – байт; ch – однобайтовый символ;

w – слово; f – флаг;

l – длинное слово; fn – функция;

u – беззнаковое; p – указатель;

с – счетчик; d – разность двух пре-х

cz – строка; и т.д.

3. Служебные слова – это слова, с которыми в языке жестко сопоставлены определённые смысловые значения и которые не могут быть использованы для других целей. Это имена операторов, библиотечных функций, команды препроцессора и так далее. Этим слова нельзя использовать для создания имен своих функций, переменных…

ДАННЫЕ В ПРОГРАММЕ НА СИ

Каждая программа оперирует с данными . Они присутствуют в программе в виде переменных и констант.

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

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

Константы

Константы - это фиксированные значения. Значение, будучи установлено, больше не меняется. Константы бывают различных типов. Типы отличаются по принципу размещения в памяти ЭВМ, а для человека по виду записи. В Си существует 7 ключевых слов, используемых для указания на различные типы данных: int, long, short, unsigned, char, float, double.

Типы констант :

a) Целые и длинные целые . Записываются в десятичной, восьмеричной и шестнадцатеричной системе счисления. Они могут быть знаковые и беззнаковые.

Десятичная система: целые константы занимают 16 бит памяти, и принимают диапазон значений: -32768 до +32767 (2 15) . Если константа беззнаковая, то диапазон удваивается: 0 до 65535 (за счет того, что 15-й разряд – знаковый используется под число). Для обозначения беззнакового числа используют суффикс u (unsigned), например 123u.

Если число больше 40000, то компилятор автоматически преобразует его в отрицательное число, поэтому суффикс u обязателен:40000u. В примере 123u компилятору все равно – есть суффикс или его нет, так как это число входит в диапазон 32767.

Длинное целое занимает 32 бита , диапазон значений

± 2147483648 (знаковое длинное – long). Если вы поставили суффикс l , то, несмотря на число, будет занято 32 бита. Например: -5326l

0 – 4294967295 беззнаковое длинное - (unsigned long). Диапазон увеличивается за счет 31-го бита. Используются суффиксы ul , например, 32659ul.

Восьмеричная система :

Если число начинается с цифры 0, оно интерпретируется как восьмиричное число

16 битов 0 ¸ 077777

0100000 ¸ 0177777u

32 бита 0200000 ¸ 01777777777l

020000000000 ¸ 037777777777ul

Шестнадцатеричная система :

Если число начинается с символа 0х, то оно интерпретируется как шестнадцатиричное

16 битов 0x0000 ¸ 0x7FFF

0x8000 ¸ 0xEFFFu

32 бита 0x10000 ¸ 0x7FFFFFFFl

0x80000000 ¸ 0xFFFFFFFFul

b) Вещественные константы . Это числа с плавающей точкой. Значение имеет дробную часть. По умолчанию все вещественные константы имеют тип двойной точности double . Занимают в памяти 8 байт (даже если 0,0). Диапазон значений ±1*10 ± 307 , можно записать и в научной форме, например: 0,5е+15 или

1,2е-3=1,2*10 -8 =0,0012.

Принудительно можно задать формат одинарной точности float . Число будет занимать 4 байта , используется суффикс f (5.7 f). Соответсвенно диапазон сужается ±1*10 ± 37

А также расширенной точности long double – 10 байт . (3.14L)

Знак + можно не писать. Разрешается опускать либо десятичную точку, либо экспоненциальную часть, но не одновременно (.2; 4е16). Можно не писать дробную либо целую часть, но не одновременно (100.; .8е-5)

c) Символьные константы. Это набор символов, используемых в ЭВМ.

Делятся на 2 группы: печатные и не печатные (управляющие коды). Символьная константа включает в себя только 1 символ, который необходимо заключить в апострофы и занимает 1 байт памяти.

Любой символ имеет своё двойное представление в таблице ASCII. В программе символьные константы вводятся в одинарных кавычках, при компиляции в программу подставляется числовое значение символа из ASCII. Один символ занимает 1 байт.

Символ "А" "a" " " "\n"

Его код 65 97 32 10

Как целый тип данных "A"=0101 8 , 01000001 2 , 41 16 , 65 10 . Коды запоминать не надо.

Управляющие коды начинаются с символа \ и тоже заключаются в апострофы. Наиболее распространенные управляющие коды:

\n – переход на новую строку

\t – табуляция (сдвиг курсора на некоторое фиксированное значение)

\b – шаг назад (сдвиг на одну позицию назад)

\r – возврат каретки (возврат к началу строки)

\f – подача бланка (протяжка бумаги на 1 страницу)

\’ - апостроф

\” - кавычки

Последние три знака могут выступать символьными константами, а также применяться в функции printf() , поэтому применение их в качестве символов может привести к ошибке. Например, если мы хотим вывести строку «Символ \ называется слеш», то оператор должен выглядеть так:

рrintf(«Символ \\ называется слеш»);

a) Строковые константы - содержат последовательность из 1 и более символов, заключённых в " ". Расходуется по 1 байту на любой символ + 1байт на так называемый ноль-символ - признак конца строки. Ноль-символ – не цифра ноль, он означает, что количество символов в строке (N) должно быть на 1 байт больше (N+1), чтобы обозначать конец строки (компилятор его прибавляет сам автоматически). Например: «строка текста» занимает (13+1) байт;

«Мир» -

Из чего состоит программа

Для начала стоит понять, что программу нельзя читать и писать как книгу: от корки до корки, сверху вниз, строку за строкой. Любая программа состоит из отдельных блоков. Начало блока кода в C/C++ обозначается левой фигурной скобкой { , его конец - правой фигурной скобкой } .

Блоки бывают разных видов и какой из них когда будет исполняться зависит от внешних условий. В примере минимальной программы вы можете видеть 2 блока. В этом примере блоки называются определением функции . Функция - это просто блок кода с заданным именем, которым кто-то затем может пользоваться из-вне.

В данном случае у нас 2 функции с именами setup и loop . Их присутствие обязательно в любой программе на C++ для Arduino. Они могут ничего и не делать, как в нашем случае, но должны быть написаны. Иначе на стадии компиляции вы получите ошибку.

Классика жанра: мигающий светодиод

Давайте теперь дополним нашу программу так, чтобы происходило хоть что-то. На Arduino, к 13-му пину подключён светодиод. Им можно управлять, чем мы и займёмся.

void setup() { pinMode(13 , OUTPUT) ; } void loop() { digitalWrite(13 , HIGH) ; delay(100 ) ; digitalWrite(13 , LOW) ; delay(900 ) ; }

Скомпилируйте, загрузите программу. Вы увидите, что каждую секунду светодиод на плате помигивает. Разберёмся почему этот код приводит к ежесекундному миганию.

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

Теперь давайте поймём в каком порядке исполняются сами блоки, т.е. функции setup и loop . Не задумывайтесь пока что значат конкретные выражения, просто понаблюдайте за порядком.

    Как только Arduino включается, перепрошивается или нажимается кнопка RESET , «нечто» вызывает функцию setup . То есть заставляет исполняться выражения в ней.

    Как только работа setup завершается, сразу же «нечто» вызывает функцию loop .

    Как только работа loop завершается, сразу же «нечто» вызывает функцию loop ещё раз и так до бесконечности.

Если пронумеровать выражения по порядку, как они исполняются, получится:

void setup() { pinMode(13 , OUTPUT) ; ❶ } void loop() { digitalWrite(13 , HIGH) ; ❷ ❻ ❿ delay(100 ) ; ❸ ❼ … digitalWrite(13 , LOW) ; ❹ ❽ delay(900 ) ; ❺ ❾ }

Ещё раз напомним, что не стоит пытаться воспринимать всю программу, читая сверху вниз. Сверху вниз читается только содержимое блоков. Мы вообще можем поменять порядок объявлений setup и loop .

void loop() { digitalWrite(13 , HIGH) ; ❷ ❻ ❿ delay(100 ) ; ❸ ❼ … digitalWrite(13 , LOW) ; ❹ ❽ delay(900 ) ; ❺ ❾ } void setup() { pinMode(13 , OUTPUT) ; ❶ }

Результат от этого не изменится ни на йоту: после компиляции вы получите абсолютно эквивалентный бинарный файл.

Что делают выражения

Теперь давайте попробуем понять почему написанная программа приводит в итоге к миганию светодиода.

Как известно, пины Arduino могут работать и как выходы и как входы. Когда мы хотим чем-то управлять, то есть выдавать сигнал, нам нужно перевести управляющий пин в состояние работы на выход. В нашем примере мы управляем светодиодом на 13-м пине, поэтому 13-й пин перед использованием нужно сделать выходом.

Это делается выражением в функции setup:

PinMode(13 , OUTPUT) ;

Выражения бывают разными: арифметическими, декларациями, определениями, условными и т.д. В данном случае мы в выражении осуществляем вызов функции . Помните? У нас есть свои функции setup и loop , которые вызываются чем-то, что мы назвали «нечто». Так вот теперь мы вызываем функции, которые уже написаны где-то.

Конкретно в нашем setup мы вызываем функцию с именем pinMode . Она устанавливает заданный по номеру пин в заданный режим: вход или выход. О каком пине и о каком режиме идёт речь указывается нами в круглых скобках, через запятую, сразу после имени функции. В нашем случае мы хотим, чтобы 13-й пин работал как выход. OUTPUT означает выход, INPUT - вход.

Уточняющие значения, такие как 13 и OUTPUT называются аргументами функции . Совершенно не обязательно, что у всех функций должно быть по 2 аргумента. Сколько у функции аргументов зависит от сути функции, от того как её написал автор. Могут быть функции с одним аргументом, тремя, двадцатью; функции могут быть без аргументов вовсе. Тогда для их вызова круглые скобка открывается и тут же закрывается:

NoInterrupts() ;

На самом деле, вы могли заметить, наши функции setup и loop также не принимают никакие аргументы. И загадочное «нечто» точно так же вызывает их с пустыми скобками в нужный момент.

Вернёмся к нашему коду. Итак, поскольку мы планируем вечно мигать светодиодом, управляющий пин должен один раз быть сделан выходом и затем мы не хотим вспоминать об этом. Для этого идеологически и предназначена функция setup: настроить плату как нужно, чтобы затем с ней работать.

Перейдём к функции loop:

void loop() { digitalWrite(13 , HIGH) ; delay(100 ) ; digitalWrite(13 , LOW) ; delay(900 ) ; }

Она, как говорилось, вызывается сразу после setup . И вызывается снова и снова как только сама заканчивается. Функция loop называется основным циклом программы и идеологически предназначена для выполнения полезной работы. В нашем случае полезная работа - мигание светодиодом.

Пройдёмся по выражениям по порядку. Итак, первое выражение - это вызов встроенной функции digitalWrite . Она предназначена для подачи на заданный пин логического нуля (LOW , 0 вольт) или логической единицы (HIGH , 5 вольт) В функцию digitalWrite передаётся 2 аргумента: номер пина и логическое значение. В итоге, первым делом мы зажигаем светодиод на 13-м пине, подавая на него 5 вольт.

Как только это сделано процессор моментально приступает к следующему выражению. У нас это вызов функции delay . Функция delay - это, опять же, встроенная функция, которая заставляет процессор уснуть на определённое время. Она принимает всего один аргумент: время в миллисекундах, которое следует спать. В нашем случае это 100 мс.

Пока мы спим всё остаётся как есть, т.е. светодиод продолжает гореть. Как только 100 мс истекают, процессор просыпается и тут же переходит к следующему выражению. В нашем примере это снова вызов знакомой нам встроенной функции digitalWrite . Правда на этот раз вторым аргументом мы передаём значение LOW . То есть устанавливаем на 13-м пине логический ноль, то есть подаём 0 вольт, то есть гасим светодиод.

После того, как светодиод погашен мы приступаем к следующему выражению. И снова это вызов функции delay . На этот раз мы засыпаем на 900 мс.

Как только сон окончен, функция loop завершается. По факту завершения «нечто» тут же вызывает её ещё раз и всё происходит снова: светодиод поджигается, горит, гаснет, ждёт и т.д.

Если перевести написанное на русский, получится следующий алгоритм:

    Поджигаем светодиод

    Спим 100 миллисекунд

    Гасим светодиод

    Спим 900 миллисекунд

    Переходим к пункту 1

Таким образом мы получили Arduino с маячком, мигающим каждые 100 + 900 мс = 1000 мс = 1 сек.

Что можно изменить

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

Вы можете подключить внешний светодиод или другое устройство, которым нужно «мигать» на другой пин. Например, на 5-й. Как в этом случае должна измениться программа? Мы должны всюду, где обращались к 13-му пину заменить номер на 5-й:

Компилируйте, загружайте, проверяйте.

Что нужно сделать, чтобы светодиод мигал 2 раза в секунду? Уменьшить время сна так, чтобы в сумме получилось 500 мс:

void setup() { pinMode(5 , OUTPUT) ; } void loop() { digitalWrite(5 , HIGH) ; delay(50 ) ; digitalWrite(5 , LOW) ; delay(450 ) ; }

Как сделать так, чтобы светодиод при каждом «подмигивании» мерцал дважды? Нужно поджигать его дважды с небольшой паузой между включениями:

void setup() { pinMode(5 , OUTPUT) ; } void loop() { digitalWrite(5 , HIGH) ; delay(50 ) ; digitalWrite(5 , LOW) ; delay(50 ) ; digitalWrite(5 , HIGH) ; delay(50 ) ; digitalWrite(5 , LOW) ; delay(350 ) ; }

Как сделать так, чтобы в устройстве были 2 светодиода, которые мигали бы каждую секунду поочерёдно? Нужно общаться с двумя пинами и работать в loop то с одним, то с другим:

void setup() { pinMode(5 , OUTPUT) ; pinMode(6 , OUTPUT) ; } void loop() { digitalWrite(5 , HIGH) ; delay(100 ) ; digitalWrite(5 , LOW) ; delay(900 ) ; digitalWrite(6 , HIGH) ; delay(100 ) ; digitalWrite(6 , LOW) ; delay(900 ) ; }

Как сделать так, чтобы в устройстве были 2 светодиода, которые переключались бы на манер железнодорожного светофора: горел бы то один то другой? Нужно просто не выключать горящий светодиод тут же, а дожидаться момента переключения:

void setup() { pinMode(5 , OUTPUT) ; pinMode(6 , OUTPUT) ; } void loop() { digitalWrite(5 , HIGH) ; digitalWrite(6 , LOW) ; delay(1000 ) ; digitalWrite(5 , LOW) ; digitalWrite(6 , HIGH) ; delay(1000 ) ; }

Можете проверить другие идеи самостоятельно. Как видите, всё просто!

О пустом месте и красивом коде

В языке C++ пробелы, переносы строк, символы табуляции не имеют большого значения для компилятора. Там где стоит пробел, может быть перенос строки и наоборот. На самом деле 10 пробелов подряд, 2 переноса строки и ещё 5 пробелов - это всё эквивалент одного пробела.

Пустое пространство - это инструмент программиста, с помощью которого можно или сделать программу понятной и наглядной, или изуродовать до неузнаваемости. Например, вспомним программу для мигания светодиодом:

void setup() { pinMode(5 , OUTPUT) ; } void loop() { digitalWrite(5 , HIGH) ; delay(100 ) ; digitalWrite(5 , LOW) ; delay(900 ) ; }

Мы можем изменить её так:

void setup( ) { pinMode(5 , OUTPUT) ; } void loop () { digitalWrite(5 ,HIGH) ; delay(100 ) ; digitalWrite(5 ,LOW) ; delay(900 ) ; }

Всё, что мы сделали - немного «поработали» с пустым пространством. Теперь можно наглядно видеть разницу между стройным кодом и нечитаемым.

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

1. Всегда, при начале нового блока между { и } увеличивайте отступ. Обычно используют 2 или 4 пробела. Выберите одно из значений и придерживайтесь его всюду.

Плохо:

void loop() { digitalWrite(5 , HIGH) ; delay(100 ) ; digitalWrite(5 , LOW) ; delay(900 ) ; }

Хорошо:

void loop() { digitalWrite(5 , HIGH) ; delay(100 ) ; digitalWrite(5 , LOW) ; delay(900 ) ; }

2. Как и в естественном языке: ставьте пробел после запятых и не ставьте до.

Плохо:

DigitalWrite(5 ,HIGH) ; digitalWrite(5 , HIGH) ; digitalWrite(5 ,HIGH) ;

Хорошо:

DigitalWrite(5 , HIGH) ;

3. Размещайте символ начала блока { на новой строке на текущем уровне отступа или в конце предыдущей. А символ конца блока } на отдельной строке на текущем уровне отступа:

Плохо:

void setup() { pinMode(5 , OUTPUT) ; } void setup() { pinMode(5 , OUTPUT) ; } void setup() { pinMode(5 , OUTPUT) ; }

Хорошо:

void setup() { pinMode(5 , OUTPUT) ; } void setup() { pinMode(5 , OUTPUT) ; }

4. Используйте пустые строки для разделения смысловых блоков:

Хорошо:

Ещё лучше:

void loop() { digitalWrite(5 , HIGH) ; delay(100 ) ; digitalWrite(5 , LOW) ; delay(900 ) ; digitalWrite(6 , HIGH) ; delay(100 ) ; digitalWrite(6 , LOW) ; delay(900 ) ; }

О точках с запятыми

Вы могли заинтересоваться: зачем в конце каждого выражения ставится точка с запятой? Таковы правила C++. Подобные правила называются синтаксисом языка . По символу; компилятор понимает где заканчивается выражение.

Как уже говорилось, переносы строк для него - пустой звук, поэтому ориентируется он на этот знак препинания. Это позволяет записывать сразу несколько выражений в одной строке:

void loop() { digitalWrite(5 , HIGH) ; delay(100 ) ; digitalWrite(5 , LOW) ; delay(900 ) ; }

Программа корректна и эквивалентна тому, что мы уже видели. Однако писать так - это дурной тон. Код гораздо сложнее читается. Поэтому если у вас нет 100% веских причин писать в одной строке несколько выражений, не делайте этого.

О комментариях

Одно из правил качественного программирования: «пишите код так, чтобы он был настолько понятным, что не нуждался бы в пояснениях». Это возможно, но не всегда. Для того, чтобы пояснить какие-то не очевидные моменты в коде его читателям: вашим коллегам или вам самому через месяц, существуют так называемые комментарии.

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

/* Функция setup вызывается самой первой, при подаче питания на Arduino А это многострочный комментарий */ void setup() { // устанавливаем 13-й пин в режим вывода pinMode(13 , OUTPUT) ; } void loop() { digitalWrite(13 , HIGH) ; delay(100 ) ; // спим 100 мс digitalWrite(13 , LOW) ; delay(900 ) ; }

Как видите, между символами /* и */ можно писать сколько угодно строк комментариев. А после последовательности / / комментарием считается всё, что следует до конца строки.

Итак, надеемся самые основные принципы составления написания программ стали понятны. Полученные знания позволяют программно управлять подачей питания на пины Arduino по определённым временны́м схемам. Это не так уж много, но всё же достаточно для первых экспериментов.




Top