Метки. Безусловный переход
Директивы препроцессора
Есть специальные команды, которые не компилируются, а лишь указывают препроцессору на необходимость выполнения некоторых действий. Директивы начинаются с символа #.
#include <имя_файла> - добавить в данное место содержимое файла, файл содержится в специальном каталоге подключаемых файлов;
#include "имя_файла" — аналогично #include<…>, но для файла из текущего каталога.
#define идентификатор [строка_замещения] - заменяет все идентификаторы от директивы до конца файла на строку замещения.
Есть модификация данной директивы, позволяющая определять макро-функции:
#define идентификатор (список_аргументов) строка_замещения
#define WIDTH 80
#define LENGTH (WIDTH + 10) //скобки необходимы для сохранения приоритета после замены
#define test(f1, f2) (f1 * f2) //пример определения макро-функции
В макро подстановках могут быть использованы специальные символы и функции:
# — преобразует аргумент в константную строку (заключает аргумент в двойные кавычки)
## — «склеивает» строки
#undef идентификатор - отменяет директиву define, после данной директивы замен не производится.
#if константное_выражение, #elif константное_выражение, #else, #endif предназначены для условной компиляции.
В директиве #if может быть использована функция defined(имя_макроидентификатора), возвращающая 1, если макроподстановка с заданным именем определена, и 0 в противном случае.
Пример:
#if WIDTH > 50 //WIDTH должен быть определен как макрос
… // будет скомпилировано, только если WIDTH > 50
#elif defined(WIDTH)
… //будет скомпилировано, если WIDTH был определен, //но предыдущее условие не выполнено
#endif //конец участка условной компиляции
… // будет скомпилировано независимо от условий
#ifdef, #ifndef — директивы являются аналогом #if defined, #if!defined.
Идентификатор с последующим двоеточием является меткой. Метка является адресом оператора, следующего за меткой. Используется в операторах switch и goto. Областью видимости метки является функция, то есть переход может быть осуществлен только внутри функции, а в разных функциях имена меток могут повторяться. Более того, метки имеют независимое пространство имен, то есть имя метки может повторять имя другого объекта, при этом компилятор их будет различать.
Пример:
int s=0, i=0;
l1: s+=i++;
if (i<100) goto l1;
Дополнительные средства организации безусловного перехода, позволяющие производить переход, в том числе, между функциями, определены в библиотеке stdjmp.h.
В языке С загружаемая и исполняемая программа называется модулем. Модуль —самая крупная часть программы. Компилятор оформляет модуль в виде четырех сегментов — сегмента кода (text в англоязычной литературе), сегментов данных (data), стека (stack) и динамического сегмента (extend). Каждый сегмент представляет собой непрерывную область памяти и вместе они образуют виртуальное адресное пространство процесса. В оперативной памяти ЭВМ сегменты могут располагаться не связанно друг с другом, что облегчает для ОС организацию мультипрограммного режима работы. Размеры сегментов и способы адресации данных внутри них определяются компилятором на основании так называемых моделей памяти, задаваемых программистом при компиляции.
Модуль может быть образован из одного или нескольких программных файлов, которые в свою очередь могут содержать описания одной или нескольких функций, которые в свою очередь могут включать один или несколько блоков — частей текста, заключенных в фигурные скобки { и }. Таким образом, иерархия структурных единиц в языке С выглядит следующим образом