Скачиваний:
2
Добавлен:
03.01.2024
Размер:
1.18 Mб
Скачать
Брайэн Керниган

СПбГУТ им. проф. М.А. Бонч-Бруевича Кафедра программной инженерии и вычислительной техники (ПИ и ВТ)

ПРОГРАММИРОВАНИЕ

Единственный способ изучать новый язык программирования - писать на нем программы.

Лекция 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

Соседние файлы в папке Лекции