1. Что такое программа на Си. Компиляция программы. Заголовочный файл. Версии программы и контроль включения. Структура программы на языках С и С . Функции С и С . Перегрузка функций в С . Ссылки. Функции с переменным числом параметров. - keykranz/oop_ex GitHub Wiki
Что такое программа на Си
Программа на Си - набор файлов, включающий директивы препроцессора, объявления переменных. Один из файлов должен содержать функцию с именем main
(но не обязательно, программа может начинаться с любой другой функции). Иными словами, программа на языке Си является набор подпрограмм (функций), внешних по отношению друг к другу (по стандарту).
Любая функция может вызвать любую другую, в том числе вызвать саму себя.
Исключением является функция main()
- в Си++ функция main()
саму себя вызвать не может. При выполнении консольного приложения, написанного на языке Си, операционная система компьютера передаёт управление функции с именем main()
. Функцию main()
нельзя вызывать из других функций программы, она является управляющей.
Можно опустить return
- функция будет возвращать 0.
Компиляция программы
Объявления необходимы компилятору. Объявлять можно один раз, определять - сколько угодно. Компилятор подставляет константы.
В С и С++ каждый файл компилируется раздельно, либо с помощью makefile
.
Получение исполняемого файла *.exe
:
-
Препроцессирование - удаление комментариев, замена
#define
, подключение заголовочных файлов*.h
(путем копирования содержимого). Для избежания повторного копирования используется#pragma once
или#ifndef G_H
. -
Компиляция - перевод написанного на языке C++ кода в код ассемблера.
-
Ассемблирование - перевод из кода ассемблера в машинный код. Получаем объектный файл с расширением
*.obj
. -
Компоновка/линковка - объединение объектных файлов в один исполняемый
*.exe
.
#pragma once
исключает множественное включение файлов.
Заголовочный файл
Заголовочные файлы - описание типов, констант, библиотеки, функций, логически вынесенных в другой исходный файл.
Что можно, а что нельзя определять в заголовочном файле:
- Определять переменные нельзя. Мы конечно можем это сделать, и на этапе компиляции проблем не будет, но сборщик покажет множественное определение - ошибочка.
- То же самое касается функций. В заголовочном файле описываются только прототипы функций.
- К языковой константе компилятор относится как к макросу, поэтому в заголовочном можно определять константу.
- Аналогично с типами - типы тоже можно определять в заголовочном файле.
То есть все константы и типы выносим в заголовочный, а так же прототипы функций.
Версии программы и контроль включения
-
Debug version. Заголовочные файлы подключаем напрямую в
.срp
, в нужные.h
ставим пометки, что подключили. При смене заголовочного перекомпилируются только те файлы, в которые он включался, а значит быстрее идет сборка. -
Realese version. Подключаем заголовочные файлы в другие заголовочные файлы. При этом, при изменении заголовочного файла, пересобираются не только заинтересованные
.cpp
, но и все те, в которые включен тот заголовок, куда подключали именно этот заголовок. Долга сборка, но понятные взаимосвязи.
Супер дополнение! Пунктирные линии - один из вариантов, либо debug, либо release. fg.h
- заголовочный файл, в котором будет только определение констант.
Контролировать включение с помощью #ifndef
- уникальное имя файла. Проверка происходит на этапе подключения.
#ifndef F_H
#define F_H
...
#endif
#pragma once
- дает гарантию того, что файл будет включен один раз (зависит от версии компилятора). Во многих средах отсутствует.
Ссылки
Структуру по значению передавать плохо, так как происходит копирование в стек, а это занимает время. Лучше по ссылке или указателю. Но у указателей есть проблема - контроль (сложно проверить корректность, только на NULL).
При передаче переменной по значению, происходит копирование памяти. При передаче объекта - создается новый объект - копия передаваемого.
int isNegative (int x); int a=3, b; b=a; isNegative(a); //происходит КОПИРОВАНИЕ памяти, передача по значению
В ООП удобно оперировать не копиями объектов, а оригиналами, поэтому вводится понятие ссылки:
Int& ref_a = a; //ссылка должна быть проинициализирована и не может изменяться, указывать на другую переемнную;
реф_а указывает на ту же память что и а.
Ссылка (alias) - ещё одно имя того же самого данного.
Ссылка это не тип данных. Ссылка является «вторым именем» переменной а, ссылается на ту же память. В основном они применяются для передачи параметров в функции: void inc(int& a) { a++; }
– фактически происходит передача адреса, по которому надо изменять значения – однако мы не используем *разыменование.
На низком уровне ссылки хоть ничем не отличается от указателя, но идет контроль! Преимущество использования ссылок перед использованием указателя: безопасная работа с памятью. Ссылка позволяет проконтролировать выделение памяти и определение переменных.
// Пример, демонстрирующий принцип работы ссылки
int i;
int& ai = i;
ai = 2; // аналогично, что i = 2;
О возврате. Нельзя возвращать ссылку на локальную переменную. Возврат по ссылке нужен для формирования левого выражения = , чтобы присвоить переменной нужное значение.
int& max(int *A, int n)
{
int imax=0;
for
if (A[imax]>A[i])
imax = I;
return A[imax]
}
max(B,n) = 0;
Const int& refc_a = a; //константная ссылка – по ней НЕЛЬЗЯ изменять значение, например через refc_a++; или refc_a =;
Перегрузка функций
В Си++ можно создавать разные функции с одинаковыми именами - использовать перегрузку функций. Перегрузка – когда одно и то же имя может соответствовать нескольким функциям, если различаются их параметры.
На перегрузку функции влияет:
- Разное количество принимаемых параметров.
- Разный тип переменных.
- const значение функции/метода. Если объект константный, то будет вызываться const метод, иначе не const.
Примечание о том, что значит модификатор const у метода. Константный метод - это метод, который гарантирует, что не будет изменять объект или вызывать неконстантные методы класса (поскольку они могут изменить объект). Соответственно, для константных объектов нельзя вызывать неконстантные методы.
Тип возвращаемой переменной не имеет значение.
// Пример функции возведения в квадрат
int sqr(int x); // для целых
double sqr(double x); // для дробных
int sqr(const int x) const; // для const целых
unsigned abs(int);
double abs(double);
int sum(int, int);
double sum(double, double, double)
Параметры по-умолчанию: void sort (int *A, int n, bool isAcs=true);
параметр isAcs будет тру, если не указано обратное. Допускается вызов sort(arr,5)
и sort(arr,5,false)
, равно как и sort(arr,5,true)
. Параметры по умолчанию обязаны идти в конце списка параметров.
Параметры по умолчанию
В Си++ один или несколько аргументов функции могут задаваться по умолчанию. Для каждого параметра значение по умолчанию можно указать не более одного раза, но каждое последующее объявление функции, а также определение функции может назначать параметрам значения по умолчанию. Параметры по умолчанию должны быть последними в списке параметров.
// Пример: функция сортировки по возрастанию массива вещественных чисел
void sort(double *arr, int count, int key = 0);
// key показывает направление сортировки (0 - по возрастанию, 1 - по убыванию).
// По умолчанию сортировка будет по возрастанию
// (key = 0, если в функцию передаются только два параметра - указатель на массив
// и количество элементов в массиве).
Функции с переменным числом параметров
В Си возможны функции с переменным числом параметров. Параметры передаются в стек, начиная с конца. В голове стека - первый параметр.
// Примеры функций суммирования
int sum(int num, ...); // явным параметром передается
// количество суммируемых целых чисел
int sum(int a, int b, ...); // суммирование прекращается,
// если очередное слагаемое равно 0
Если количество или типы некоторых аргументов неизвестны, надо заменить их многоточием. При этом:
- хотя бы один аргумент должен быть известен (иначе откуда функция узнает количество и типы аргументов?)
- известные аргументы должны быть в начале списка
- ИЛИ один из обязательных передаваемых параметров информирует о количестве необязательных параметров, ИЛИ закреплено дно стека (например известно, что последним переданным параметр будет 0).
Некоторые нововведения с++:
- Классы
- New, delete
- Конструкторы и деструкторы
- Template
- Перегрузка функций и операторов
- throw/catch
- Умные указатели
- Ссылки