- •Алфавит языка Си
- •Идентификаторы (имена) языка Си
- •Ключевые слова
- •Константы (литералы)
- •Комментарии
- •Пример программы на Си
- •Последовательность обработки программы на Си
- •Термины
- •2.1. Концепция типа данных
- •2.2. Базовые типы данных
- •2.2. Атрибуты объектов
- •2.2.1. Класс памяти
- •2.2.2. Область (сфера) действия, связанного с объектом идентификатора
- •2.2.3. Область видимости объекта
- •2.2.4. Продолжительность существования объекта (время жизни)
- •2.2.5. Тип компоновки (связывания)
- •2.3. Объявления, определения и описания в языке Си
- •2.4. Объявления переменных стандартных типов
- •2.5. Преобразования типов
- •Термины
- •3.1. Определение и общая классификация операторов
- •3.2. Последовательно выполняемые операторы
- •3.3. Операции языка Си
- •3.4. Приоритеты и порядок выполнения операций, тип результата выражения
- •Тип результата выражения арифметической бинарной операции
- •Даны X, y (значения вводятся с клавиатуры). Вычислить a, если
- •Термины
- •4.1. Условный оператор
- •4.2. Переключатель
- •4.3. Операторы циклов
- •4.4. Оператор безусловной передачи управления
- •4.5. Оператор возврата из функции
- •4.6. Оператор выхода из цикла или переключателя
- •4.7. Оператор перехода к следующей итерации цикла
- •Термины
- •5.1. Указатели
- •5.2. Ссылки
- •5.3. Массивы
- •5.3.1. Одномерные массивы
- •Int a[100]; // Объявление массива из 100 элементов типа int
- •Инициализация массива
- •Массивы и указатели
- •Динамические массивы
- •5.3.2. Многомерные массивы
- •Инициализация многомерных массивов
- •Динамические многомерные массивы
- •Указатель на массив указателей и указатель на массив
- •Int ** p1; // Указатель на массив указателей
- •Int (*p2)[10]; // Указатель на массив из 10 элементов типа int
- •Термины
- •6.1. Структуры
- •Int X; // Поле структуры
- •Int X; // Поле структуры
- •Int X; // Поле структуры
- •Инициализация структуры
- •Int year, page; // Год издания и число страниц
- •6.2. Объединения
- •6.3. Битовые поля структур и объединений
- •Int a1: 10; // Битовое поле из 10 бит
- •Int a2: 14; // Битовое поле из 14 бит
- •Int :6; // Пропускаем 6 бит
- •6.4. Директива определения типа typedef
- •Термины
- •7.1. Определение, описание и вызов функции
- •7.2. Использование значений параметров по умолчанию
- •7.3. Изменение значений скалярных параметров в функциях
- •7.3.1. Передача параметров в функции по значению
- •7.3.1. Передача параметров в функции по указателю (по ссылке)
- •7.4. Передача в функцию массивов
- •7.4.1. Передача в функцию массивов, не являющихся строками
- •7.4.2. Передача в функцию строк
- •7.5. Функции с переменным количеством параметров
- •7.6. Рекурсивные функции
- •7.7. Подставляемые (inline) функции
- •7.8. Указатели на функции
- •7.10. Шаблоны функций
- •7.11. Возможные параметры функции main
- •Термины
- •8.1. Общие сведения о вводе-выводе
- •8.2. Стандартные потоки ввода-вывода
- •8.3. Функции для вывода в поток stdout
- •8.4. Функции для считывания из потока stdin
- •8.5. Ввод- вывод в файлы Открытие файла
- •Закрытие файла
- •Определение конца файла
- •Функции записи в файл
- •Функции чтения из файла
- •Функции позицирования в файлах
- •Функции для сброса буферов
- •Термины
- •9.1. Стадии и основные команды препроцессорной обработки
- •9.2. Замены в тексте
- •9.3. Макроподстановки
- •9.4. Включение текстов из файлов
- •9.5. Условная компиляция
- •9.10. Указания компилятору
- •9.6. Директива нумерации строк
- •9.7. Директива обработки ошибок
- •9.8. Директивы # и ##
- •9.9. Заранее определенные препроцессорные идентификаторы
- •Термины
9.3. Макроподстановки
Макрос – это средство замены одной последовательности символов другой (замена в тексте простейшая форма макроса).
Большими возможностями обладают макроопределения с параметрами.
Формат макроподстановки с параметрами:
#define <идентификатор>(<список_параметров>) <текст>
Примеры:
#define max(a, b) a<b?b:a
Вхождение в программу max(x, 10) заменяется на x<10?10:x
#define abs(x) x>=0?x:-x
Вхождение в программу abs(a) заменяется на a>=0?a:-a
Отличие макросов от функций
-
Функции имеют код (за исключением inline-функций) в одном экземпляре, а коды макроса вставляются в программу столько раз, сколько используется макрос, причем подстановка для макроса осуществляется всегда.
-
Функции работают с определенными типами параметров, макрос пригоден для обработки параметров любого типа, допустимых в выражении строки замещения.
Механизм перегрузки и шаблоны функций в Си++ позволяют решать те же задачи.
Ниже представлен пример с использованием макросов. В примере вместо скобок { } используются слова begin/BEGIN и end/END, как в зыке Паскаль, на самом деле в тексте эти слова заменяются на соответствующие скобки. Также представлен пример макроса с параметрами.
#include <stdio.h>
#define begin {
#define end }
#define BEGIN {
#define END }
#define max(a, b) a>b?a:b
int main(int argc, char* argv[])
{
int A[10];
int i;
int x=10, y=5, z;
for(i=0; i<10; i++) begin
A[i]=i*i;
printf("%d ", A[i]);
end
z=max(x, y); // z=x>y?x:y;
printf("z=%d", z);
return 0;
}
9.4. Включение текстов из файлов
Директива выполняет простое действие: вставляет текст из одного файла в другой файл в заданном месте. Формат директивы:
#include “(путь_к_файлу)_имя_файла”
#include <(путь_к_файлу)_имя_файла>
Когда используются символы “” файл в первую очередь ищется в текущем каталоге, а затем в системных, в которые установлена среда разработки, а когда <>, то файл ищется в первую очередь в системных каталогах, а затем в текущем. Чаще всего используются включения заголовочных файлов, содержащих заголовки функций и другие общие объявления.
9.5. Условная компиляция
С помощью директив условной компиляции некоторые фрагменты исходного текста программы могут включаться в текст или исключаться из текста во время компиляции в зависимости от условий. Следует отметить, что если фрагмент текста не включается на компиляцию, то в нем могут быть какие угодно синтаксические ошибки, они на результат работы компилятора влиять не будут. Директивы условной компиляции имеют три различные формы, формат которых представлен ниже.
Первая форма:
#if <целочисленное_выражение1>
[<текст>]
[#elif < целочисленное_выражение2>
<текст>]
[#elif < целочисленное_выражение3>
<текст>]
…..
[#else
<текст>]
#endif
Целочисленное выражение не должно содержать операцию sizeof, приведение типов и константы, определенные через enum. Директива работает так, если целочисленное выражение после #if истинно (отлично от 0), то на компиляцию включается текст после #if, остальные тексты после #elif и #else на компиляцию не попадают. Если после #if выражение ложно (равно 0), то последовательно проверяются выражения после #elif, когда находится выражение истинное (отличное от 0), то на компиляцию попадает один фрагмент после этого #elif. Если не одно #elif не сработало, все целочисленные выражения ложные, то на компиляцию поступает текст после #else до #endif (если директива #else есть).
Ниже представлен пример, в котором на печать выводится else, фрагменты исходного текста, которые не поступают на компиляцию, набраны с синтаксическими ошибками.
#include <stdio.h>
#define _M 0
int main(int argc, char* argv[])
{
#if _M
pr3464572intf("1");
#elif 0
prin4363tf("2");
#elif 0
pri35252ntf("3");
#else
printf("else");
#endif
return 0;
}
Вторая форма:
#ifdef <идентификатор>
[<текст>]
[#elif < целочисленное_выражение2>
<текст>]
[#elif < целочисленное_выражение3>
<текст>]
…..
[#else
<текст>]
#endif
В этой форме первое условие считается истинным, если идентификатор после #ifdef до этого объявлен, как препроцессорный в директиве #define, в этом случае на компиляцию поступает текст после #ifdef, если идентификатор до этого не объявлен, как препроцессорный, то далее условия проверяются, как в первой форме.
Третья форма:
#ifndef <идентификатор>
[<текст>]
[#elif < целочисленное_выражение2>
<текст>]
[#elif < целочисленное_выражение3>
<текст>]
…..
[#else
<текст>]
#endif
В отличие от второй формы первое условие считается истинным, если идентификатор после #ifndef до этого не объявлен, как препроцессорный в директиве #define, а ложном в том случае, если идентификатор объявлен, как препроцессорный, в этом случае далее условия проверяются, как в первой форме.
Вместо директив #ifdef и #ifndef можно использовать более старые формы:
#if defined(<идентификатор>)
#if !defined(<идентификатор>)
defined(<идентификатор>) – может использоваться в качестве ограниченного константного выражения, например, после #elif .
Директивы условной компиляции могут использоваться для отладочных печатей, для защиты заголовочных файлов от повторного включения, а также для повышения переносимости программ.
Пример отладочных печатей, их все можно убрать из текста изменив одно строчку программы.
#include <stdio.h>
#define Pechat
int main(int argc, char* argv[])
{
int x=10;
int y=167;
#ifdef Pechat
printf("\nx=%d", x);
#endif
#ifdef Pechat
printf("\ny=%d", y);
#endif
printf("\nRez=%d", x+y);
return 0;
}
Также заголовочные файлы должны иметь защиту от повторного включения, например, все стандартные заголовочные файлы имеют защиту от повторного включения. Пример структуры файла stdio.h:
#ifndef _INC_STDIO
#define _INC_STDIO
……..
// Основное содержание файла
…….
#endif /* _INC_STDIO */
