- •СПбГУТ им. проф. М.А. Бонч-Бруевича Кафедра программной инженерии и вычислительной техники (ПИ и
- •1. Общая характеристика языка Си
- •Рейтинг TIOBE Index
- •Рейтинг IEEE Spectrum
- •Рейтинг Stack Overflow
- •Общая характеристика языка Си
- •Структура программы на языке Си
- •Структура программы на языке Си
- •Компиляция и интерпретация
- •Структура программы на языке Си
- •2. Директивы препроцессора
- •Директивы препроцессора. Макроопределения и макровызовы
- •3. Понятие о функции
- •Понятие о функции
- •Понятие о функции
- •Простейшие средства ввода-вывода
- •5. Простейшие средства ввода-вывода
- •Простейшие средства ввода-вывода
- •Простейшие средства ввода-вывода
- •Справочно: Форматированный вывод данных. Функция printf( )
- •Справочно: Форматированный ввод данных. Функция scanf( )
СПбГУТ им. проф. М.А. Бонч-Бруевича Кафедра программной инженерии и вычислительной техники (ПИ и ВТ)
ПРОГРАММИРОВАНИЕ
Единственный способ изучать новый язык программирования - писать на нем программы.
Лекция 3: Язык Си. Начальные сведения
1.Общая характеристика языка Си.
Структура программы, написанной на языке СИ.
2.Директивы препроцессора.
3.Понятие о функции. Простейшие средства ввода-вывода.
4.Примеры простейших программ, написанных на языке Си (по ходу лекции).
Санкт-Петербург, 2023г.
1. Общая характеристика языка Си
Почему Си?
Один из наиболее популярных языков программирования
Синтаксис языка Си является основой для многих других языков программирования (С++, Java, JavaScript, С# и пр.)
Программы на Си хорошо переносимы между различными платформами (компиляторы Си существуют, практически, для всех типов процессоров)
Сочетает в себе черты языков низкого и высокого уровней
Простейшая программа
Адекватной замены этому языку нет и не предвидится, есть такие классы задач, для которых просто нет других подходящих языков; придётся, как следствие, «терпеть» Си таким, каков он есть.
Принять этот язык как феномен вам поможет понимание того, откуда он взялся, почему он именно таков, почему, несмотря на все свои «выверты» и «выкрутасы», этот язык продолжает удерживать первое место по популярности и почему, наконец, программиста, не знающего Си, всегда и везде будут воспринимать как сотрудника второго сорта, даже если писать на Си от него не требуется.
2
Рейтинг TIOBE Index
Рейтинг TIOBE Index построен на оценке результатов поисковых запросов, содержащих название языка. Логика этого индекса очень проста:
«Если язык ищут в поисковых системах, то он популярен».
Интересно то, что C++ ни разу не смог превысить по популярности C.
www.tiobe.com/tiobe-inde x
3
Рейтинг IEEE Spectrum
Ежегодный рейтинг IEEE Spectrum Top Programming Language
использует 11 метрик из 8-ми источников, включая поисковые запросы, упоминания в твитере и даже упоминания в вакансиях на работу программиста.
С одной стороны этот рейтинг использует больше данных, но с другой стороны во многих источниках данные имеют связанный характер.
Чем больше публикуются вакансий на некоторый язык программирования, тем больше запросов будет в поисковых системах.
То есть у новых языков больше шансов попасть на вершину рейтинга.
Важностью особенностью рейтинга IEEE является то, что рейтинг интерактивный и можно поиграть с параметрами. В этом рейтинге лидирует Python.
https://spectrum.ieee.org/static/interactive-the-top-programmin g-languages-2020
4
Рейтинг Stack Overflow
Сайт Stack Overflow — это площадка, на которой разработчики могут задавать и отвечать на вопросы по программированию. Этот сайт имеет около 40 миллионов посещений в месяц. Есть русскоязычная версия сайта: ru.stackoverflow.com
Этот рейтинг рассчитывается на основе опроса разработчиков. В 2020 году было опрошено более 65 000 разработчиков и составлен рейтинг языков программирования. Скорее это рейтинг языков, которые вызывают вопросы. В этом рейтинге лидером стал JavaScript.
https://insights.stackoverflow.com/survey/2020
Такая популярность вполне объяснима, сейчас JavaScript бурно развивается и каждая новая возможность вызывает массу вопросов, поэтому программисты идут на сайт Stack Overflow, чтобы задать вопросы.
Любопытно, что в этом рейтинге Cи не попал даже в первую десятку. Видимо, язык настолько прост и понятен, что вопросов не вызывает.
5
Общая характеристика языка Си
|
Из всей истории языка Си выделяются три основных фактора, |
позволяющих понять Си как явление: |
|
|
во-первых, язык был создан в качестве заменителя языка |
|
ассемблера ; |
во-вторых, одним из важнейших соображений при его |
|
|
создании была простота реализации; |
в-третьих, язык был, что называется, «слеплен» под |
|
|
конкретную задачу, вставшую здесь и сейчас, и делали его, |
|
как говорят в таких случаях, «на коленке». |
|
Вряд ли Дэннис Ритчи, в то время ещё очень молодой, мог |
предполагать, что создаваемый им язык переживёт своего |
|
создателя и, уже просуществовав больше сорока лет (а |
|
описываемые события происходили в начале 1970-х годов), всё |
|
ещё не будет выказывать никаких признаков надвигающейся |
|
старости; сейчас можно достаточно смело предсказывать, что |
|
ещё по меньшей мере полтора-два десятка лет языку Си ничего |
|
не грозит, даже если вдруг кому-то удастся создать ему |
|
полноценную замену. |
|
С технологической точки зрения ситуация сейчас выглядит так. |
Имеются по меньшей мере две области задач, где единственной |
|
альтернативой Си оказывается язык ассемблера: |
|
|
это, во-первых, ядра операционных систем; |
|
и, во-вторых, прошивки для микроконтроллеров — |
|
специализированных компьютеров, используемых для |
|
управления техникой (лифтами, стиральными машинами и т. |
п.); даже билет на метро представляет собой не что иное, как компьютер на основе микроконтроллера.
К вопросу о том, почему это так и чем здесь не устраивают другие языки, мы вернёмся позже, пока просто отметим, что работа на языке ассемблера оказывается в десятки раз более трудоёмкой, причём если когда-то давно ещё можно было ссылаться на более высокую эффективность ассемблерных программ, то сейчас оптимизаторы кода, встроенные прямо в компилятор, добиваются таких результатов по быстродействию, что человек, работая вручную, в большинстве случаев просто не может сделать лучше.
Поэтому, когда дело доходит до низкоуровневого
программирования, язык ассемблера используется лишь для тех редких и незначительных по объёму фрагментов, которые не могут быть сделаны даже на Си ; примером такого фрагмента может служить точка входа в обработчик прерывания в ядре ОС или, например, обращение к портам ввода-вывода в драйвере, и это обычно несколько строчек.
Большую часть низкоуровневой программы пишут именно на Си, что позволяет экономить дорогостоящее время программистов.
Разработка велась на микроЭВМ |
|
DEC PDP-11: |
|
|
Оперативная память – 24Кб |
|
Из них используется ОС – 12 Кб |
Задачи: |
|
|
Разработка нового языка |
|
программирования |
Разработка на нем |
|
|
операционной системы |
6
Структура программы на языке Си
Общая структура программы на языке Си имеет вид:
<директивы препроцессора>
<определение типов пользователя - typedef> <описание прототипов функций> <определение глобальных переменных>
<функции>
Программа, написанная на языке Си, состоит из одной или нескольких функций, причем одна функция обязательна имеет идентификатор (имя) main()
Назначение функции main() – управление работой всей программы.
Функции main(), как правило, не имеет параметров и не возвращает результат (наличие круглых скобок обязательно).
Исполняемый файл, полученный из программы на Си, обычно устроен так, что после загрузки его в оперативную память управление получит код, скомпилированный из функции main().
С некоторой натяжкой можно считать, что функцию main() вызывает операционная система при старте программы.
Структура простой программы
#include <stdio.h> //содержит стандартные //функции файлового ввода-вывода
void main()
{ //Начало функции main
рrintf ("Это работает функция main! "); return 0; } //Окончание функции main
#include <stdio.h> int main (void)
{
printf ("Hello, World!\n"); return 0;
}
Строчка printf("Hello, world\n");
представляет собой вызов библиотечной функции, которая называется printf.
Отметим один крайне важный идеологический момент.
В отличие от Паскаля, где операторы ввода-вывода являются частью языка, в язык Си как таковой никакие средства ввода-вывода не входят.
Функция printf не является частью языка Си по меньшей мере в том смысле, что компилятор о ней ничего не знает .
Более того, сама функция printf написана на Си.
Мы использовали функцию printf, чтобы напечатать строку, но её возможности гораздо шире: она умеет печатать значения всех встроенных типов языка Си, причём целые числа можно печатать в разных системах счисления, можно управлять количеством печатаемых знаков и т. п.
Буква f в названии функции происходит от слова formatted, то есть эта функция осуществляет форматированный вывод.
Основные возможности printf мы рассмотрим на других занятиях. Отметим ещё один момент.
Функция printf — это действительно функция; она возвращает целое число, равное количеству напечатанных символов, то есть мы могли бы, например, написать:
x = printf("Hello, world\n");
7
Структура программы на языке Си
Отдельного рассмотрения заслуживает выражение
"Hello, world\n"
которое представляет собой строковую константу или, как часто говорят, строковый литерал.
Следует обратить внимание на двойные кавычки; апострофы в Си тоже используются, но для других целей. Кроме того, внимание привлекает конструкция \n;
это обозначение символа перевода строки, то есть символа с кодом 10.
Можно вспомнить, что в Паскале мы в подобной ситуации применяли оператор writeln / write:
writeln(’Hello, world’); write(’Hello, world’#10);
то есть заставляли нашу программу сначала напечатать данную строку, а затем перевести строку на печати, то есть фактически напечатать ещё и символ перевода строки.
В вышеприведённом примере мы просто включили этот символ в состав печатаемой строки.
Обратим внимание на символ точки с запятой.
В принципе, роль этого символа в языке Си подобна паскалевской, но есть одно важное отличие:
Если в Паскале точка с запятой разделяла операторы, то в Си точка с запятой является частью синтаксиса оператора.
#include <stdio.h> int main (void)
{
printf ("Hello, World!\n"); return 0;
}
|
Рассмотрим теперь следующую строку, «return 0;». |
|
|
Слово return в переводе с английского означает |
|
«возврат»; в языке Си это оператор возврата из функции. |
||
|
Он делает две вещи: |
|
|
|
во-первых, работа функции на этом заканчивается, |
|
|
что можно, например, использовать для досрочного |
|
|
её завершения (подобно паскалевскому exit); |
|
во-вторых, его параметр — выражение, написанное |
|
|
|
после слова return, в данном случае 0 — задаёт то |
|
|
значение, которое вернёт функция (вспомним, что |
|
|
наша функция main описана как возвращающая |
|
|
целое число). |
|
В данном случае наша функция main вернёт число 0. |
|
0 |
Значение, возвращаемое из main, предназначается ОС, а |
|
в данном случае означает, что всё в порядке, т. е. |
программа, завершаясь, считает, что возложенную на неё миссию успешно выполнила.
8
|
|
Структура программы на языке Си |
|
|
||
|
|
#include <stdio.h> |
|
|||
|
|
|
|
|
||
Нам осталось рассмотреть, пожалуй, самую |
|
int main (void) |
|
|||
|
{ |
|
||||
заковыристую строку в программе: |
|
printf ("Hello, World!\n"); |
|
|||
директиву |
#include <stdio.h> |
|
|
|
||
|
|
return 0; |
|
|||
Как уже, |
несомненно, догадались, |
эта директива в |
|
} |
|
|
тексте программы заменяет сама себя на полное |
Важно понимать, что |
|
|
|||
в этом файле содержится только |
||||||
содержимое файла stdio.h, а нужно это, чтобы |
заголовок функции printf, а самой функции там нет; |
|||||
компилятор узнал про функцию printf — как уже |
отсюда используемый суффикс «.h», от слова header, то |
|||||
говорилось, сам по себе он о ней не знает. |
есть «заголовок» — в английской терминологии это |
|||||
Здесь следует отметить сразу несколько интересных |
называется header file, а по-русски — «заголовочный |
|||||
моментов: |
файл». |
|
|
|||
Обращают на себя внимание используемые угловые |
Всё, что компилятор узнает, увидев заголовок — это что |
|||||
скобки <>, которые означают, что включаемый файл |
где-то (и притом совершенно неважно, где) есть функция |
|||||
следует искать в системных директориях; |
с таким-то именем, принимающая столько-то параметров |
|||||
точнее говоря, считается, что именно так следует |
таких-то типов; как функция выглядит, что она делает — |
|||||
включать любой файл, который не является сам по себе |
этого компилятору знать не нужно. |
|||||
частью нашей программы; |
Дело в том, что компилятор генерирует не готовый |
|||||
когда же мы пишем программу, состоящую из многих |
машинный код, а объектный модуль, в котором пока что |
|||||
файлов, то для включения своих собственных файлов |
не хватает некоторых адресов; в данном случае |
|||||
мы используем #include с параметром в двойных |
результатом работы компилятора становится модуль, не |
|||||
кавычках “ “, например: |
содержащий самой функции printf. |
|||||
#include "mymodule.h" |
Вместо неё модуль содержит указание на то, что |
|||||
файл stdio.h — это вполне реальный файл; скорее всего, |
редактору связей (линкеру) следует откуда-то добыть |
|||||
функцию с таким именем, а её адрес подставить куда |
||||||
он находится в вашей системе в директории |
||||||
следует. |
|
|
||||
/usr/include, так что вы можете просмотреть его, |
|
|
||||
Иначе говоря, реальная функция printf появится в нашей |
||||||
например, командой less: |
||||||
программе только на этапе окончательной сборки, когда |
||||||
less /usr/include/stdio.h |
||||||
работа компилятора будет завершена. |
9
Компиляция и интерпретация
Технология компиляции
Текст |
|
|
|
|
|
|
|
|
|
|
|
|
Текстовый |
|
|
Файл |
|
Препро- |
|
Файл |
|||
программы |
|
|
|
(ИТ) |
|
|
|
|
(ИМ) |
||
|
|
редактор |
|
|
|
|
|
цессор |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Транслятор |
Файл |
Линкер |
Файл |
(компиля- |
(ОМ) |
(компонов- |
(ИМ) |
тор) |
… |
щик) |
|
|
|
|
Загрузчик |
Файл
(ОМ)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Исходные |
|
|
Исполняемая |
|
|
Результаты |
данные |
|
|
|
|
||
|
|
программа |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Программу на интерпретируемом языке
непосредственно выполняет без предварительного перевода программа-интерпретатор.
ЯВУ не зависит от внутренних машинных языков целевых процессоров, поэтому программы, написанные на языках высокого уровня, требуют перевода в машинные коды с помощью специальных программ –
трансляторов (компиляторов или
интерпретаторов), т.е. языки программирования могут быть реализованы как компилируемые и интерпретируемые.
Программа на компилируемом языке при помощи компилятора преобразуется (компилируется) в набор инструкций для данного типа процессора (машинный код – двоичные коды инструкций конкретного процессора), который далее преобразуется (компонуется) в исполнимый модуль.
Технология интерпретации
Текст
программы
Транслятор Результаты
(интерпретатор)
Исходные данные
10