
- •Происхождение языка с
- •Язык среднего уровня
- •Структурированный язык
- •Язык программирования
- •Компиляторы против интерпретаторов
- •Вид программ на с
- •Библиотеки и компоновка
- •Раздельная компиляция
- •Карта памяти с-программы
- •Переменные, константы, операторы и выражения
- •Идентификаторы
- •Типы данных
- •Модификаторы типов
- •Модификаторы доступа
- •Объявление переменных
- •Локальные переменные
- •Формальные параметры
- •Глобальные переменные
- •Спецификаторы хранения
- •Статические переменные
- •Статические локальные переменные
- •Статические глобальные переменные
- •Регистровые переменные
- •Оператор присваивания
- •Многочисленное присваивание
- •Преобразование типов при присваивании
- •Инициализация переменных
- •Константы
- •Символьные константы с обратным слэшем
- •Операторы
- •Арифметические операторы
- •Увеличение и уменьшение
- •Операторы отношения и логические операторы
- •Битовые операторы
- •Оператор ?
- •Операторы указания & и *
- •Оператор sizeof
- •Оператор «запятая»
- •Операторы [ ] u ()
- •Приоритеты в с
- •Выражения
- •Преобразование типов в выражениях
- •Принудительные преобразования
- •Пробелы и круглые скобки
- •Сокращенные операторы в с
- •Операторы управления программой
- •Истина и ложь в с
- •Операторы выбора
- •Вложенные if
- •Лесенка if-else-if
- •Оператор ?
- •Вложенные операторы switch
- •Вариации цикла for
- •Бесконечный цикл
- •Циклы for без тела
- •Метки и goto
- •Функции
- •Оператор return
- •Выход из функции
- •Возвращаемые значения
- •Значения, возвращаемые функцией main()
- •Правила видимости для функций
- •Аргументы функции
- •Передача по значению и передача по ссылке
- •Создание передачи по ссылке
- •Передача массивов в функции
- •Аргументы функции main()
- •Функции, возвращающие нецелые значения
- •Использование прототипов функции
- •Прототипы стандартных библиотечных функций
- •Создание прототипов функций, не имеющих параметров
- •Возврат указателей
- •Рекурсия
- •Сопоставление классического и современного объявления параметров
- •Указатели на функции
- •Особенности реализации
- •Параметризированные функции и функции общего назначения
- •Эффективность
- •Массивы
- •Одномерный массив
- •Создание указателя на массив
- •Передача одномерных массивов в функции
- •Двумерные массивы
- •Массивы строк
- •Многомерные массивы
- •Индексация с помощью указателей
- •Размещение массивов
- •Инициализация массива
- •Инициализация безразмерных массивов
- •Пример программы игры в крестики-нолики
- •Указатели
- •Указатели - это адреса
- •Переменные-указатели
- •Операторы для работы с указателями
- •Выражения с указателями
- •Присваивание указателей
- •Арифметические действия с указателями
- •Сравнение указателей
- •Динамическое выделение и указатели
- •Указатели на константы
- •Указатели на константы
- •Указатели на константы
- •Указатели и массивы
- •Указатели на символьные массивы
- •Массивы указателей
- •Указатели на указатели - многочисленное перенаправление
- •Инициализация указателей
- •Указатели на функции
- •Проблемы, связанные с указателями
- •Структуры, объединения и определяемые пользователем типы
- •Структуры
- •Доступ к членам структуры
- •Присваивание структур
- •Массивы структур
- •Программа инвентаризации
- •Передача структур в функции
- •Передача членов структур в функции
- •Передача всей структуры в функцию
- •Указатели на структуры
- •Объявление указателя на структуру
- •Использование указателей на структуру
- •Массивы и структуры в структурах
- •Битовые поля
- •Объединения
- •Перечисления
- •Использование sizeof для обеспечения переносимости
- •Ввод, вывод, потоки и файлы
- •Потоки и файлы
- •Текстовые потоки
- •Двоичные потоки
- •Консольный ввод/вывод
- •Чтение и запись символов
- •Чтение и запись строк: gets() и puts()
- •Форматированный консольный ввод/вывод
- •Печать символов
- •Вывод чисел
- •Вывод адресов
- •Спецификатор %n
- •Модификаторы формата
- •Спецификатор минимума ширины поля
- •Спецификатор точности
- •Выровненный вывод
- •Работа с другими типами данных
- •Модификаторы * u #
- •Спецификаторы формата
- •Ввод чисел
- •Ввод беззнаковых целых
- •Чтение отдельных символов с помощью scanf()
- •Чтение строк
- •Ввод адреса
- •Спецификатор %n
- •Использование множества сканирования
- •Пропуск нежелательных специальных символов
- •Обычные символы в управляющей строке
- •В scanf() следует передавать адреса
- •Модификаторы формата
- •Подавление ввода
- •Файловая система ansi с
- •Указатель на файл
- •Открытие файла
- •Запись символа
- •Чтение символа
- •Использование fopen(), getc(), putc() и fclose()
- •Использование feof()
- •Две расширенные функции: getw() и putw()
- •Работа со строками: fgets() и fputs()
- •Fseek() и произвольный доступ
- •Удаление файлов
- •Работа с консолью
- •Препроцессор и комментарии
- •Директивы условной компиляции
- •Использование defined
- •Операторы препроцессора # и ##
- •Предопределенные макросы
- •Комментарии
Директивы условной компиляции
Существует несколько директив условной компиляции, позволяющих изменять порядок компиляции программы в зависимости от состояния системы. Данный процесс называется условной компиляцией и широко используется при разработке коммерческого программного обеспечения, предоставляющего и поддерживающего много различных версий одной и той же программы.
#if, #else, #elif и #endif
Если после #if константное выражение принимает истинное значение, то код между #if и #endif компилируется, в противном случае код пропускается. Директива #endif используется для обозначения конца блока #if. Стандартный вид #if следующий: #if константное_выражение последовательность операторов #endif
Например: /* простой пример с #if */ #include <stdio.h> #define MAX 100 int main(void) { #if MAX>99 printf("Compiled for array greater than 99.\n"); #endif return 0; }
Данная программа выводит сообщение на экран, поскольку, как определено в программе, МАХ имеет значение больше 99. Данный пример демонстрирует очень важный момент: выражение, следующее зa #if, вычисляется на этапе компиляции, следовательно, оно должно содержать ранее определенные идентификаторы и константы, а не переменные.
Работа #else во многом похожа на работу оператора else — она предоставляет альтернативный вариант, если #if содержит ложное состояние. Предыдущий пример можно расширить следующим образом:
/* простой пример с #if / #else */ #include <stdio.h> #def ine MAX 10 int main(void) { # if MAX>99 printf("Compiled for array greater than 99.\n"); #else printf("Compiled for small array.\n"); #endif return 0; }
В данном случае MAX определяется так, чтобы значение было меньше 99, в результате чего компилируется не код, соответствующий #if, а код, соответствующий #else. Следовательно, выводится сообщение «Compiled for small array».
Обратим внимание, что #else используется для обозначения конца блока #if и начала блока #else. Это делается потому, что может быть только один #endif, связанный c #if.
#elif означает «иначе если» и используется для построения лесенки if-else-if с целью определения различных опций компиляции. За #elif следует константное выражение. Если выражение истинно, то блок кода компилируется и остальные выражения не проверяются. В противном случае рассматривается следующий блок. Стандартный вид #elif следующий: #if выражение последовательность операторов #elif выражение 1 последовательность операторов #elif выражение 2 последовательность операторов #elif выражение 3 последовательность операторов #elif выражение 4 последовательность операторов ... #elif выражение N последовательность операторов #endif
Например, следующий фрагмент использует значение ACTIVE_COUNTRY для определения денежного знака: #define US 0 #define ENGLAND 1 #define FRANCE 2 #define ACTIVE_COUNTRY US #if ACTIVE_COUNTRY==US char currency[] = "dollar"; #elif ACTIVE_COUNTRY==ENGLAND char currency[] = "pound"; #else char currency[] = "franc"; #endif
#if и #elif могут быть вложенными. Если это имеет место, то каждый #endif, #else или #elif ассоциируется с ближайшим #if или #elif. Например, следующее совершенно корректно: #if МАХ>100 #if SERIAL_VERSION int port = 198; #elif int port = 200; #endif #else char out_buffer[100] ; #endif
В Borland С++ в операторе #if можно использовать оператор времени компиляции sizeof. Например, следующая программа определяет, компилируется программа для больших или маленьких массивов: #if (sizeof(char *) == 2) printf("Program compiled for small array."); #else printf("Program compiled for large array."); #endif
#ifdef u #ifndef
Другой метод условной компиляции состоит в использовании директив #ifdef и #ifndef, что соответственно означает «если определено» и «если не определено». Стандартный вид #ifdef следующий: #ifdef имя_макроса последовательность операторов #endif
Если имя макроса определено ранее в операторе #define, то последовательность операторов, стоящих между #ifdef и #endif, будет компилироваться. Стандартный вид #ifndef следующий: #ifndef имя_макроса последовательность операторов #endif
Если имя макроса не определено ранее в операторе #define, то последовательность операторов, стоящих между #ifdef и #endif, будет компилироваться.
Kaк #ifdef, так и #ifndef могут использовать оператор #else, но нe #elif. Например: #include <stdio.h> #define TED 10 int main(void) { #ifdef TED printf("Hi Ted\n"); #else printf("Hi anyone\n"); #endif #ifndef RALPH printf("RALPH not defined\n"); #endif return 0; }
выводит «Hi Ted» и «RALPH not defined». Если TED не определен, то выведется «Hi anyone», a за ним «RALPH not defined».
#ifdef и #ifndef можно вкладывать друг в друга так же, как и #if.
#undef
Директива #undef используется для снятия определения макроса. Она имеет следующий вид: #undef имя_макроса
Например: #define LEN 100 #define WIDTH 100 char array[LEN][WIDTH]; #undef LEN #undef WIDTH /* в данный момент как LEN, так и WIDTH не определены */ Как LEN, так и WIDTH определены, пока не встретится соответствующий #undef.
Основное назначение #undef состоит в локализации имен макросов только в тех частях, где они необходимы.