Вы находитесь на странице: 1из 403

Contents

Документация по языку C
Справочник по языку C
Справочник по языку C
Организация справочника по языку C
Организация справочника по языку C
Содержание данного руководства
Соответствие ANSI
Элементы языка C
Элементы языка C
Токены C
Токены C
Пробелы
Комментарии в C
Оценка токенов
Ключевые слова в C
Идентификаторы C
Идентификаторы C
Многобайтовая кодировка и расширенные символы
Триграфы
Константы в C
Константы в C
Константы с плавающей запятой в C
Константы с плавающей запятой в C
Ограничения на константы с плавающей запятой
Целочисленные константы в C
Целочисленные константы в C
Целочисленные типы
Пределы целых чисел в C и C++
Символьные константы в C
Символьные константы в C
Символьные типы
Кодировка исполнения
Escape-последовательности
Спецификации восьмеричных и шестнадцатеричных символов
Строковые литералы в C
Строковые литералы в C
Тип для строковых литералов
Хранение строковых литералов
Объединение строковых литералов
Максимальная длина строки
Знаки препинания и специальные символы
Структура программы
Структура программы
Исходные файлы и исходные программы
Файлы с исходным кодом и исходные программы
Директивы препроцессору
Прагмы C
Объявления и определения в C
Объявления и определения функций
Blocks
Пример программы
Функция main и выполнение программ
Функция main и выполнение программ
Использование wmain
Описание аргумента
Расширение аргументов-заполнителей
Анализ аргументов командной строки C
Настройка обработки командной строки C
Время жизни, область, видимость и компоновка
Время жизни, область, видимость и компоновка
Время существования
Область и видимость
Сводка времени существования и видимости
Компоновка
Компоновка
Внутренняя компоновка
Внешняя компоновка
Без компоновки
Пространства имен
Объявления и типы
Объявления и типы
Общие сведения об объявлениях
Классы хранения в C
C - классы хранения
Описатели классов хранения для объявлений внешнего уровня
Описатели классов хранения для объявлений внутреннего уровня
Описатели классов хранения для объявлений внутреннего уровня
Описатель класса хранения auto
Описатель класса хранения register
Описатель класса хранения static
Описатель класса хранения extern
Описатели классов хранения с объявлениями функций
Описатели типов C
Описатели типов C
Описатели и эквиваленты типов данных
Описатели типов
Деклараторы и объявления переменных
Деклараторы и объявления переменных
Простые объявления переменных
Объявления перечислений C
Объявления структур
Объявления структур
Битовые поля в C
Хранение и выравнивание структур
Объявления объединений
Объявления объединений
Хранение объединений
Объявления массивов
Объявления массивов
Хранение массивов
Объявления указателей
Объявления указателей
Хранение адресов
Основанные указатели (C)
Абстрактные деклараторы в C
Интерпретация сложных деклараторов
Инициализация
Инициализация
Инициализация скалярных типов
Инициализация агрегатных типов
Инициализация строк
Хранение базовых типов
Хранилище базовых типов
Тип char
Тип int
Целочисленные типы размеров C
Тип float
Тип double
Тип long double
Неполные типы
Объявления Typedef
Расширенные атрибуты классов хранения в C
Расширенные атрибуты классов хранения в C
Импорт и экспорт DLL
Naked (C)
Локальное хранилище потока
Выражения и присваивания
Выражения и присваивания
Операнды и выражения
Операнды и выражения
Первичные выражения в C
Первичные выражения в C
Идентификаторы в первичных выражениях
Константы в первичных выражениях
Строковые литералы в первичных выражениях
Выражения в скобках
Выражения L-Value и R-Value
Постоянные выражения C
Вычисление выражений (C)
Вычисление выражений (C)
Побочные эффекты
Точки следования в C
Операторы в C
Операторы в C
Приоритет и порядок оценки
Обычные арифметические преобразования
Постфиксные операторы
Постфиксные операторы
Одномерные массивы
Многомерные массивы (C)
Вызов функции (C)
Члены структур и объединений
Постфиксные операторы увеличения и уменьшения в C
Унарные операторы C
Унарные операторы C
Префиксные операторы инкремента и декремента
Операторы косвенного обращения и взятия адреса
Унарные арифметические операторы
Оператор sizeof (C)
Операторы приведения
Операторы умножения в C
Операторы сложения в C
Операторы сложения в C
Сложение (+)
Вычитание (-)
Использование операторов сложения
Расчеты указателей
Операторы побитового сдвига
Операторы отношения и равенства в C
Побитовые операторы в C
Логические операторы в C
Оператор Conditional-Expression
Операторы присваивания C
Операторы присваивания C
Простое присваивание (C)
Составное присваивание в C
Оператор последовательного вычисления
Преобразования типов (C)
Преобразования типов (C)
Преобразования присваиваний
Преобразования присваиваний
Преобразования из целочисленных типов со знаком
Преобразования из целочисленных типов без знака
Преобразования типов с плавающей запятой
Преобразования в типы указателей и из типов указателей
Преобразования из других типов
Преобразования приведений типов
Преобразования вызова функции
Операторы (C)
Операторы (C)
Операторы (C)
Общие сведения об операторах в C
Оператор break (C)
Составной оператор (C)
Оператор continue (C)
Оператор do-while (C)
Оператор выражений (C)
Оператор for (C)
goto и помеченные операторы (C)
Оператор if (C)
Оператор NULL (C)
Оператор return (C)
Оператор switch (C)
Оператор try-except (C)
Оператор try-finally (C)
Оператор while (C)
Функции (C)
Функции (C)
Общие сведения о функциях
Общие сведения о функциях
Устаревшие формы объявлений и определений функций
Определения функций в C
Определения функций в C
Атрибуты функций
Атрибуты функций
Указание соглашений о вызовах
Встраиваемые функции
Встроенный ассемблер (C)
Функции импорта и экспорта DLL
Функции импорта и экспорта DLL
Определения и объявления (C)
Определение встраиваемых функций C с помощью dllexport и dllimport
Правила и ограничения dllimport и dllexport
Функции с атрибутом naked
Функции с атрибутом naked
Правила и ограничения при использовании функций с атрибутом naked
Вопросы, связанные с написанием кода пролога и эпилога
Класс хранения
Возвращаемый тип
Параметры
Тело функции
Прототипы функций
Вызовы функций
Вызовы функций
Аргументы
Вызовы с переменным количеством аргументов
Рекурсивные функции
Краткие сведения о синтаксисе языка C
Краткие сведения о синтаксисе языка C
Определения и соглашения
Лексическая грамматика
Лексическая грамматика
Общие сведения о токенах
Общие сведения о ключевых словах
Общие сведения об идентификаторах
Общие сведения о константах
Общие сведения о строковых литералах
Операторы (C)
Символы пунктуации
Грамматика структуры фразы
Грамматика структуры фразы
Общие сведения о выражениях
Общие сведения об объявлениях
Общие сведения об операторах
Внешние определения
Поведение, определяемое реализацией
Поведение, определяемое реализацией
Перевод: Диагностика
Среда
Среда
Аргументы функции main
Интерактивные устройства
Поведение идентификаторов
Поведение идентификаторов
Значимые символы без внешней компоновки
Значимые символы с внешней компоновкой
Верхний и нижний регистр
Знаки
Знаки
Кодировка ASCII
Многобайтовые символы
Число битов на символ
Кодировки1
Непредставимые символьные константы
Расширенные символы
Преобразование многобайтовых символов
Диапазон значений типа char
Целые числа
Целые числа
Диапазон целочисленных значений
Понижение уровня целых чисел
Битовые операции со знаком
Остатки от деления
Сдвиги вправо
Вычисления с плавающей запятой
Вычисления с плавающей запятой
Значения
Приведение целочисленных значений к значениям с плавающей запятой
Усечение значений с плавающей запятой
Массивы и указатели
Массивы и указатели
Максимальный размер массива
Вычитание указателей
Регистры: Доступность регистров
Структуры, объединения, перечисления и битовые поля
Структуры, объединения, перечисления и битовые поля
Неправильный доступ к объединению
Заполнение и выравнивание членов структуры
Знак битовых полей
Хранение битовых полей
Тип перечисления
Квалификаторы: Доступ к временным объектам
Деклараторы: максимальное число
Операторы: Пределы операторов switch
Директивы предварительной обработки
Директивы предварительной обработки
Символьные константы и условное включение
Включение имен файлов в скобках
Включение имен файлов в кавычках
Последовательности символов
Директивы pragma
Дата и время по умолчанию
Функции библиотеки
Функции библиотеки
Макрос NULL
Диагностика, напечатанная функцией assert
Тестирование символов
Ошибки домена
Потеря точности значений с плавающей запятой
Функция fmod
Функция signal (C)
Сигналы по умолчанию
Завершающие символы новой строки
Пустые строки
Символы NULL
Позиция файла в режиме добавления
Усечение текстовых файлов
Буферизация файла
Файлы нулевой длины
Имена файлов
Ограничения доступа к файлам
Удаление открытых файлов
Переименование с использованием существующего имени
Чтение значений указателя
Диапазоны чтения
Ошибки положения файла
Сообщения, создаваемые функцией perror
Выделение обнуленной памяти
Функция abort (C)
Функция atexit (C)
Имена сред
Функция system
Функция strerror
Часовой пояс
Функция clock (C)
Справочник по препроцессору в C/C++
Справочник по библиотеке времени выполнения C (CRT)
Справочник по языку C
07.05.2020 • 2 minutes to read • Edit Online

Справочник по языку C описывает язык программирования C, реализованный в Microsoft C. Руководство


организовано на основе стандарта ANSI C (иногда называется C89) и содержит дополнительные сведения
о расширениях Майкрософт для стандарта ANSI C.

Организация Справочника по языку C

Дополнительные справочные материалы по языку C++ и препроцессору см. в следующих документах:

C++ Language Reference (Справочник по языку C++)


C/C++ Preprocessor Reference (Справочник по препроцессору C/C++)
Параметры компилятора и компоновщика приведены в Образец построения C/C++.

См. также
Справочник по языку C++
Организация Справочника по языку C
07.05.2020 • 2 minutes to read • Edit Online

Элементы языка C

Структура программы

Объявления и типы

Выражения и присваивания

Операторы

Функции

Краткие сведения о синтаксисе языка C

Поведение, определяемое реализацией

См. также
Справочник по языку C
Содержание данного руководства
07.05.2020 • 2 minutes to read • Edit Online

C — гибкий язык, предоставляющий широкие возможности для программирования. При этом C накладывает
несколько ограничений на преобразование типов. Хотя возможности языка упрощают программирование,
для понимания того, как будут работать программы, необходимо хорошо знать язык. В данной книге
приведены сведения о компонентах языка C и возможностях реализации Microsoft. Синтаксис языка C
соответствует стандарту ANSI X3.159-1989, American National Standard for Information Systems -
Programming Language- C (Американский национальный стандарт для информационных систем — Язык
программирования — Язык C). Здесь и далее он называется стандартом ANSI C, хотя не является частью
этого стандарта. В статье Общие сведения о синтаксисе языка C рассмотрен синтаксис и описаны правила
чтения и использования определений синтаксиса.

Программирование на языке C++ в данной книге рассматривается. Сведения о языке C++ см. в справочнике
по языку C++.

См. также
Организация Справочника по языку C
Соответствие ANSI
07.05.2020 • 2 minutes to read • Edit Online

Microsoft C соответствует стандарту языка C, представленному в выпуске 9899:1990 стандарта ANSI C.


Расширения Microsoft для стандарта ANSI C указаны в тексте и синтаксисе данного руководства, а также в
электронной справочной документации. Поскольку расширения не являются частью стандарта ANSI C, их
применение может ограничить переносимость программ между системами. По умолчанию расширения
Microsoft включены. Чтобы отключить расширения, используйте параметр компилятора /Za. С помощью
параметра /Za весь отличный от ANSI код создает ошибки или предупреждения.

См. также
Организация Справочника по языку C
Элементы языка C
15.05.2020 • 2 minutes to read • Edit Online

В этом разделе описываются элементы языка программирования C, включая имена, числа и символы,
используемые в нем для составления программ. В синтаксисе ANSI C эти компоненты называются
токенами.

В этом разделе объясняется, как определять токены и как компилятор вычисляет их.

Рассматриваются следующие темы:

Лексемы

Комментарии

Ключевые слова

Идентификаторы

Константы

Строковые литералы

Знаки препинания и специальные символы

Раздел также включает справочные таблицы по триграфам, ограничениям на константы с плавающей


запятой, пределам целых чисел в C и C++ и escape-последовательностям.

Операторы — это символы (представленные как одним знаком, так и комбинацией знаков), которые
указывают , каким образом должны обрабатываться значения. Каждый символ интерпретируется как
единый блок, который называется токеном. Дополнительные сведения см. в разделе Операторы.

См. также
Справочник по языку C
Токены C
07.05.2020 • 2 minutes to read • Edit Online

Базовым элементом программы на языке C, распознаваемым компилятором, является токен. Токен — это
такой фрагмент текста исходной программы. который компилятор не разбивает на составные элементы.

Синтаксис
token: keyword
identifier
constant
string-literal
operator
знак препинания

NOTE
Описание соглашений о синтаксисе ANSI вы найдете во введении к статье Общие сведения о синтаксисе языка C.

Ключевые слова, идентификаторы, константы, строковые литералы и операторы, описанные в этом


разделе, являются примерами токенов. Символы пунктуации, например квадратные ( [ ] ), фигурные ( { } ) и
круглые скобки ( ( ) ) и запятая ( , ), также являются лексемами.

См. также
Элементы языка C
Пробелы
07.05.2020 • 2 minutes to read • Edit Online

Символы пробела, табуляции, перевода строки (новой строки), возврата каретки, перевода страницы и
вертикальной табуляции называются пробельными символами, поскольку они выполняют ту же функцию,
что и пробелы между словами и строками на печатной странице — они упрощают чтение. Токены
разделяются (разграничиваются) пробельными символами и другими токенами, например операторами и
символами пунктуации. При синтаксическом анализе кода компилятор C игнорирует пробельные
символы — кроме тех случаев, когда они используются как разделители или как компоненты символьных
констант или строковых литералов. Используйте пробельные символы, чтобы сделать программу более
удобочитаемой. Обратите внимание, что комментарии также обрабатываются компилятором как пробел.

См. также
Токены C
Комментарии в C
07.05.2020 • 3 minutes to read • Edit Online

Комментарий — это последовательность символов, которая начинается с косой черты и звездочки (/* ).
Компилятор воспринимает комментарий как один пробельный символ, в остальных случаях он
игнорируется. Комментарии могут включать любое сочетание символов из представимого набора
символов, который включает символы новой строки, но не включает разделитель конца комментария (*/ ).
Комментарии могут занимать несколько строк, но не могут быть вложенными.

Они могут располагаться в любом месте, где допускается использование пробельных символов. Поскольку
компилятор обрабатывает комментарий как один пробельный символ, его невозможно использовать в
составе токена. Символы, которые находятся в комментарии, компилятор игнорирует.

Комментарии используются для документирования кода. В следующем примере компилятор принимает


комментарий:

/* Comments can contain keywords such as


for and while without generating errors. */

Комментарии в коде могут находиться в той же строке, что и оператор:

printf( "Hello\n" ); /* Comments can go here */

Перед функциями или программными модулями можно вставлять блоки комментариев с описаниями.

/* MATHERR.C illustrates writing an error routine


* for math functions.
*/

Поскольку комментарии не могут содержать вложенные комментарии, то следующий пример вызовет


ошибку:

/* Comment out this routine for testing

/* Open file */
fh = _open( "myfile.c", _O_RDONLY );
.
.
.
*/

Причина ошибки в том, что компилятор распознает первое сочетание символов, */ , расположенное после
слов Open file , как конец комментария. Он пытается обработать оставшийся текст , а обнаружив символы
*/ за пределами комментария, выдает сообщение об ошибке.

Хотя с помощью комментариев можно скрывать часть кода для тестирования, для этого есть полезная
альтернатива: директивы препроцессора #if и #endif и условная компиляция. Дополнительные сведения
см. в статье Preprocessor Directives (Директивы препроцессора) в справочника по препроцессору.

Блок , относящийся только к системам Microsoft


Компилятор Microsoft также поддерживает однострочные комментарии, перед которыми ставятся две
косые черты ( // ). Если компиляция выполняется с параметром /Za (стандарт ANSI), то такие комментарии
создают ошибки. Такие комментарии невозможно расширить до второй строки.

// This is a valid comment

Комментарии, которые начинаются с двух косых черт ( // ), завершаются первым символом новой строки,
перед которым не стоит escape-символ. В следующем примере перед символом новой строки стоит
обратная косая черта ( \ ), которая создает escape-последовательность. В результате этого следующая
строка обрабатывается компилятором как часть текущей строки. Дополнительные сведения см. в статье
Escape Sequences (Escape-последовательности).

// my comment \
i++;

Поэтому оператор i++; скрыт комментарием.

В Microsoft C расширения Microsoft по умолчанию включены. Отключить их можно при помощи параметра
/Za.
Завершение блока , относящегося только к системам Майкрософт

См. также
Токены C
Оценка токенов
07.05.2020 • 2 minutes to read • Edit Online

Когда компилятор интерпретирует токены, он включает в один токен максимально возможное количество
символов, а затем переходит к следующему. Поэтому если токены не разделены пробельными символами,
они могут интерпретироваться не так, как ожидается. Рассмотрим следующее выражение:

i+++j

В этом примере компилятор сначала извлекает максимально возможный оператор ( ++ ) из


последовательности знаков "плюс", а затем обрабатывает последний знак "плюс" как оператор сложения (
+ ). Таким образом, выражение интерпретируется как (i++) + (j) , а не как (i) + (++j) . Для того чтобы
предотвратить неоднозначность и гарантировать правильное вычисление выражений, в подобных случаях
рекомендуется использовать пробелы и скобки.

Блок , относящийся только к системам Microsoft

Компилятор C обрабатывает символ CTRL+Z как индикатор конца файла. Весь текст , расположенный после
символа CTRL+Z, игнорируется.

Завершение блока , относящегося только к системам Майкрософт

См. также
Токены C
Ключевые слова в C
13.10.2020 • 4 minutes to read • Edit Online

Ключевыми словами называются слова, которые имеют особое значение для компилятора C. На 7 и 8 этапах
трансляции идентификатор не может иметь такое же написание и регистр записи, что и ключевое слово C.
Дополнительные сведения см. в разделе Этапы преобразования Справочника по препроцессору.
Дополнительные сведения об идентификаторах см. в этом разделе.

Ключевые слова стандартного языка C


В языке C используются следующие ключевые слова:

auto
break
case
char
const
continue
default
do
double
else
enum

extern
float
for
goto
if
inline 1, a
int
long
register
restrict 1, a
return

short
signed
sizeof
static
struct
switch
typedef
union
unsigned
void
volatile

while
2, a
_Alignas 2, a
_Alignof 2, a
_Atomic 2, b
_Bool 1, a
_Complex 1, b
_Generic 2, a
_Imaginary 1, b
_Noreturn 2, a
_Static_assert 2, a
_Thread_local 2, b

1 Ключевые слова, представленные в стандарте ISO C99.

2 Ключевые слова, представленные в стандарте ISO C11.

a Начиная с Visual Studio 2019


версии 16.8, эти ключевые слова поддерживаются в коде, скомпилированном
как C, если указаны параметр компилятора /std:c11 или /std:c17 .
b Начиная с Visual Studio 2019
версии 16.8, эти ключевые слова распознаются но не поддерживаются
компилятором в коде, скомпилированном как C, если указаны параметр компилятора /std:c11 или
/std:c17 .
Переопределить ключевые слова невозможно. Но с помощью директив препроцессора C можно определить
текст , который будет использоваться вместо ключевых слов.

Ключевые слова C для систем Microsoft


Стандарты ANSI и ISO C позволяют зарезервировать идентификаторы, начинающиеся с двух символов
подчеркивания, для реализаций компилятора. Поэтому в системах Microsoft действует соглашение, что
используемые в них ключевые слова начинаются с двух символов подчеркивания. Эти слова невозможно
использовать как имена идентификаторов. Описание правил именования идентификаторов, включая
использование двойных знаков подчеркивания, см. в статье об идентификаторах.

Компилятор Microsoft C распознает следующие ключевые слова и особые идентификаторы.

__asm 5
dllimport 4
__int8 5
naked 4
__based 3, 5

__except 5
__int16 5
__stdcall 5
__cdecl 5
__fastcall

__int32 5
thread 4
__declspec 5
__finally 5
__int64 5

__try 5
dllexport 4

5
__inline 5
__leave 5

3 Ключевое слово __based имеет ограниченное применение: в компиляциях для 32- и 64-разрядных
платформ.
4 Если эти ключевые слова используются с ключевым словом __declspec , они являются особыми
идентификаторами. В других контекстах они могут использоваться без ограничений.
5 Для совместимости с предыдущими версиями эти ключевые слова доступны как с двумя символами

подчеркивания в начале, так и с одним при включении расширений Microsoft.

Расширения Microsoft по умолчанию включены. Чтобы помочь в создании переносимого кода, расширения
Microsoft можно отключить, указав во время компиляции параметр /Za (Отключить расширения языка) . При
этом некоторые ключевые слова для систем Microsoft будут отключены.

Когда расширения Microsoft включены, в программах можно использовать перечисленные выше ключевые
слова. Для совместимости со стандартами большинство этих ключевых слов начинаются с двух символов
подчеркивания. Четыре исключения, dllexport , dllimport , naked и thread , используются только с
ключевым словом __declspec и поэтому не требуют двойного знака подчеркивания. Для всех остальных
ключевых слов поддерживаются версии с одним символом подчеркивания. Это сделано для обеспечения
обратной совместимости.

См. также
Элементы языка C
Идентификаторы C
13.10.2020 • 6 minutes to read • Edit Online

"Идентификаторы" или "символы" — это имена, задаваемые в программе для переменных, типов, функций
и меток. Написание и регистр символов в именах идентификаторов должны отличаться от всех ключевых
слов. Не допускается использовать ключевые слова (C или Microsoft) в качестве идентификаторов; они
зарезервированы для специального применения. Идентификатор создается путем его указания в
объявлении переменной, типа или функции. В этом примере result представляет собой идентификатор
целой переменной, а main и printf — это имена идентификаторов для функций.

#include <stdio.h>

int main()
{
int result;

if ( result != 0 )
printf_s( "Bad file handle\n" );
}

Объявленный идентификатор можно использовать в последующих операторах программы для ссылки на


соответствующее значение.

Специальный вид идентификатора, называемый меткой оператора, может использоваться в операторах


goto . (Объявления рассматриваются в разделе Объявления и типы. Метки операторов рассматриваются в
разделе Оператор goto и помеченные операторы.)

Синтаксис
identifier:
nondigit
identifier nondigit
identifier digit
nondigit: один из следующих символов:
_ a b c d e f g h i j k l mn o p q r s t u v w x y z
A B C D E F G H I J K L MN O P Q R S T U V W X Y Z
digit: один из следующих символов:
0123456789
Первый символ имени идентификатора должен принадлежать к группе nondigit (т. е., первым символом
должен быть знак подчеркивания или прописная либо строчная буква). Стандарт ANSI допускает 6
значащих символов в имени внешнего идентификатора и 31 символ для имен внутренних (внутри
функции) идентификаторов. На имена внешних идентификаторов (идентификаторов, объявленных в
глобальной области или с классом хранения extern ) могут накладываться дополнительные ограничения,
поскольку эти идентификаторы должны обрабатываться другим программным обеспечением, таким как
компоновщики.

Блок , относящийся только к системам Microsoft

Хотя стандарт ANSI допускает 6 значащих символов в именах внешних идентификаторов и 31 символ в
именах внутренних (внутри функции) идентификаторов, компилятор Microsoft C допускает 247 символов в
именах внутренних и внешних идентификаторов. Если совместимость со стандартом ANSI не требуется,
можно увеличить или уменьшить это значение по умолчанию с помощью параметра /H (ограничение
длины внешних имен).

Завершение блока , относящегося только к системам Майкрософт

В компиляторе языка C прописные и строчные буквы считаются разными символами. Эта особенность,
называемая "учетом регистра", позволяет создавать различные идентификаторы, состоящие из
одинаковых букв в различных регистрах. Например, каждый из следующих идентификаторов является
уникальным:

add
ADD
Add
aDD

Блок , относящийся только к системам Microsoft

Не выбирайте для идентификаторов имена, которые начинаются с двух символов подчеркивания или с
одного символа подчеркивания и последующей прописной буквы. Стандарт ANSI языка C разрешает
резервировать имена идентификаторов, начинающиеся с таких сочетаний символов, для использования
компилятором. Идентификаторы с областью действия на уровне файлов также не должны начинаться со
знака подчеркивания и последующей строчной буквы. Имена идентификаторов, начинающиеся с таких
символов, также зарезервированы. По принятому соглашению в системах Microsoft символ подчеркивания
и прописная букву используются в начале имен макросов, а два символа подчеркивания используются для
специальных ключевых слова систем Microsoft. Во избежание каких-либо конфликтов имен никогда не
выбирайте имена идентификаторов, которые начинаются с одного или двух символов подчеркивания или
с символа подчеркивания и последующей прописной буквы.

Завершение блока , относящегося только к системам Майкрософт

Ниже приведены примеры допустимых идентификаторов, которые соответствуют ограничениям на имена,


накладываемым стандартом ANSI или системами Microsoft:

j
count
temp1
top_of_page
skip12
LastNum

Блок , относящийся только к системам Microsoft

Хотя по умолчанию в файлах исходного кода учитывается регистр символов в идентификаторах, в


символах объектных файлов регистр не учитывается. Microsoft C обрабатывает идентификаторы в
единице компиляции с учетом регистра.

Компоновщик Microsoft учитывает регистр. Необходимо указывать все идентификаторы единообразно с


учетом регистра.

"Исходная кодировка" — это набор допустимых символов, которые могут использоваться в файлах
исходного кода. Для Microsoft C исходной кодировкой является стандартный набор символов ASCII.
Исходная кодировка и кодировка выполнения содержат символы ASCII, используемые в виде escape-
последовательностей. Сведения о кодировке выполнения см. в статье Константы символов в C.

Завершение блока , относящегося только к системам Майкрософт


У идентификатора имеется "область", т. е. область программы, в которой он определен, и "компоновка",
которая определяет , ссылается ли то же самое имя из другой области на этот же идентификатор. Эти
вопросы рассматриваются в разделе Время существования, область, видимость и компоновка.

См. также
Элементы языка C
Многобайтовая кодировка и расширенные
символы
13.10.2020 • 2 minutes to read • Edit Online

Многобайтовые символы — это символы, составленные последовательностями из одного или нескольких


байтов. Каждая последовательность байтов представляет отдельный символ в расширенном наборе
символов. Многобайтовые символы используются в таких кодировках, как Кандзи.

Расширенные символы — это коды многоязычных символов, которые всегда имеют размер 16 бит.
Символьные константы имеют тип char ; для расширенных символов используется тип wchar_t .
Поскольку расширенные символы всегда имеют фиксированный размер, их использование упрощает
программирование с использованием международных кодировок.

Строковый литерал с расширенными символами L"hello" становится массивом из шести целочисленных


значений типа wchar_t .

{L'h', L'e', L'l', L'l', L'o', 0}

Расширенные символы определены в спецификации Юникода. Преобразование между многобайтовыми и


расширенными символами выполняется процедурами библиотеки времени выполнения mbstowcs , mbtowc ,
wcstombs и wctomb .

См. также
Идентификаторы C
Триграфы
13.10.2020 • 3 minutes to read • Edit Online

Кодировка исходного кода исходных программ на языке C содержится в 7-разрядной кодировке ASCII, но в
то же время является надмножеством инвариантной кодировки ISO 646-1983. Последовательности
триграфа позволяют писать программы на языке C с использованием только инвариантной кодировки,
соответствующей стандартам ISO. Триграфы — это последовательности из трех символов (которым
предшествует два вопросительных знака), которые компилятор заменяет соответствующими знаками
пунктуации. Триграфы можно использовать в файлах исходного кода на языке C с набором символов,
который не содержит удобных графических представлений некоторых знаков пунктуации.

C++17 удаляет триграфы из языка. Поддержка триграфов может сохраняться при определяемом
реализацией сопоставлении физического исходного файла с основной кодировкой исходного кода, хотя
обычно это не рекомендуется. C++14 обеспечивает такую же поддержку триграфов как в языке C.

Visual C++ по-прежнему поддерживает подстановку триграфов, но по умолчанию она отключена.


Сведения о том, как включить подстановку триграфов, см. в статье /Zc:trigraphs (подстановка триграфов).

В следующей таблице показаны девять последовательностей триграфов. Все вхождения знаков


препинания в первом столбце файла исходного кода заменяются соответствующим символом во втором
столбце.

Последовательности триграфов
ТРИГРАФ ЗНАК ПРЕПИНАНИЯ

??= #

??( [

??/ \

??) ]

??' ^

??< {

??! |

??> }

??- ~

Триграф всегда отображается как один символ исходного кода. Преобразование триграфов происходит на
первом этапе перевода перед распознаванием escape-символов в строковых литералах и символьных
константах. Распознаются только девять триграфов, отображаемых в таблице выше. Все другие
последовательности символов остаются непреобразованными.

Последовательность escape-символов, \? , не позволяет неверно интерпретировать символьные


последовательности, напоминающие триграфы. (Сведения об escape-последовательностях см. в разделе
Escape-последовательности.) Например, при попытке напечатать строку What??! с данной инструкцией
printf

printf( "What??!\n" );

напечатанная строка имеет вид What| , так как ??! — это триграфическая последовательность, которая
заменяется символом | . Напишите инструкцию следующим образом, чтобы правильно напечатать строку:

printf( "What?\?!\n" );

В этой инструкции printf escape-символ обратной косой черты перед вторым вопросительным знаком не
позволяет неверно интерпретировать ??! как триграф.

См. также
(подстановка триграфов)
/Zc:trigraphs
Идентификаторы C
Константы в C
13.10.2020 • 2 minutes to read • Edit Online

Константа — это число, символ или символьная строка, которую можно использовать в программе в
качестве значения. Константы служат для представления значений с плавающей запятой, целых чисел,
перечислений или символов, изменение которых невозможно.

Синтаксис
constant :
  floating-point-constant
  integer-constant
  enumeration-constant
  character-constant

Константы имеют значение и тип. Константы с плавающей запятой, целочисленные константы и


символьные константы рассматриваются в следующих трех статьях. Константы перечисления
рассматриваются в статье Объявления перечислений.

См. также
Элементы языка C
Константы с плавающей запятой в C
13.10.2020 • 3 minutes to read • Edit Online

"Константа с плавающей запятой — это десятичное число, которое представляет знаковое вещественное
число. Представление знакового вещественного числа включает в себя целочисленную часть, дробную
часть и экспоненту. Константы с плавающей запятой служат для представления значений с плавающей
запятой, которые не могут быть изменены.

Синтаксис
floating-point-constant:
fractional-constant exponent-partopt floating-suffixopt
digit-sequence exponent-part floating-suffixopt
fractional-constant:
digit-sequenceopt . digit-sequence
digit-sequence .
exponent-part:
e signopt digit-sequence
E signopt digit-sequence
sign: один из указанных ниже знаков
+-
digit-sequence:
digit
digit-sequence digit
floating-suffix: один из указанных ниже знаков
flFL
Можно опустить либо цифры перед десятичной запятой (целочисленная часть значения), либо цифры
после десятичной запятой (дробная часть), но не и то и другое. Если включается только экспонента,
десятичную запятую можно опустить. Пробельные символы между цифрами или символами константы не
допускаются.

В следующих примерах показаны некоторые формы констант и выражений с плавающей запятой.

15.75
1.575E1 /* = 15.75 */
1575e-2 /* = 15.75 */
-2.5e-3 /* = -0.0025 */
25E-4 /* = 0.0025 */

Константы с плавающей запятой имеют положительное значение, если перед ними не стоит знак "минус" ( -
). А этом случае знак "минус" интерпретируется как унарный арифметический оператор изменения знака.
Константы с плавающей запятой относятся к типу float , double или long double .

Константы с плавающей запятой без суффикса f , F , l или L относятся к типу double . Если суффикс
представлен буквой f или F , константа относится к типу float . Если суффикс представлен буквой l или L ,
константа относится к типу long double . Пример:
10.0L /* Has type long double */
10.0F /* Has type float */

Обратите внимание, что компилятор Майкрософт для C внутренне представляет long double так же, как и
тип double . Дополнительные сведения о типах double , float и long double см. в статье Хранилище
базовых типов.

Целочисленную часть константы с плавающей запятой можно опустить, как показано в следующих
примерах. Число .75 можно выразить несколькими способами, включая следующие:

.0075e2
0.075e1
.075e1
75e-2

См. также
Константы в C
Ограничения на константы с плавающей запятой
07.05.2020 • 2 minutes to read • Edit Online

Блок , относящийся только к системам Microsoft

В следующей таблице представлены ограничения на значения констант с плавающей запятой. Эта


информация содержится в файле заголовка FLOAT.H.

Ограничения на константы с плавающей запятой


КОНСТАНТА ЗНАЧЕНИЕ ЗНАЧЕНИЕ

FLT_DIG Количество цифр q, при котором 6


DBL_DIG число с плавающей запятой с q 15
LDBL_DIG десятичными цифрами можно 15
округлить в представление с
плавающей запятой и обратно без
потери точности.

FLT_EPSILON Наименьшее положительное число x, 1,192092896e-07F


DBL_EPSILON при котором x + 1,0 не равно 1,0. 2,2204460492503131e-016
LDBL_EPSILON 2,2204460492503131e-016

FLT_GUARD 0

FLT_MANT_DIG Количество цифр для основания, 24


DBL_MANT_DIG заданного константой FLT_RADIX , в 53
LDBL_MANT_DIG значащей части числа с плавающей 53
запятой. Основание содержит два
знака; следовательно, эти значения
определяют разряды.

FLT_MAX Максимальное представимое число с 3,402823466e+38F


DBL_MAX плавающей запятой. 1,7976931348623158e+308
LDBL_MAX 1,7976931348623158e+308

FLT_MAX_10_EXP Максимальное целое число, при 38


DBL_MAX_10_EXP котором число 10, возведенное в 308
LDBL_MAX_10_EXP степень этого числа, является 308
представимым числом с плавающей
запятой.

FLT_MAX_EXP Максимальное целое число, при 128


DBL_MAX_EXP котором значение FLT_RADIX , 1024
LDBL_MAX_EXP возведенное в степень этого числа, 1024
является представимым числом с
плавающей запятой.

FLT_MIN Минимальное положительное 1,175494351e-38F


DBL_MIN значение. 2,2250738585072014e-308
LDBL_MIN 2,2250738585072014e-308
КОНСТАНТА ЗНАЧЕНИЕ ЗНАЧЕНИЕ

FLT_MIN_10_EXP Минимальное отрицательное целое -37


DBL_MIN_10_EXP число, при котором число 10, -307
LDBL_MIN_10_EXP возведенное в степень этого числа, -307
является представимым числом с
плавающей запятой.

FLT_MIN_EXP Минимальное отрицательное целое -125


DBL_MIN_EXP число, при котором значение -1021
LDBL_MIN_EXP FLT_RADIX , возведенное в степень -1021
этого числа, является представимым
числом с плавающей запятой.

FLT_NORMALIZE 0

FLT_RADIX Основание экспоненциальной 2


_DBL_RADIX формы представления. 2
_LDBL_RADIX 2

FLT_ROUNDS Режим округления для сложения 1 (приблизительно)


_DBL_ROUNDS чисел с плавающей запятой. 1 (приблизительно)
_LDBL_ROUNDS 1 (приблизительно)

Обратите внимание, что в будущих реализациях информация из приведенной выше таблицы может
отличаться.

Завершение блока , относящегося только к системам Майкрософт

См. также
Константы с плавающей запятой в C
Целочисленные константы в C
15.05.2020 • 3 minutes to read • Edit Online

Целая константа является десятичным (основание 10), восьмеричным (основание 8) или


шестнадцатеричным (основание 16) числом, представляющим целое значение. Целые константы служат
для представления целых значений, которые не могут быть изменены.

Синтаксис
integer-constant:
decimal-constant integer-suffixopt
octal-constant integer-suffixopt
hexadecimal-constant integer-suffixopt
decimal-constant:
nonzero-digit
decimal-constant digit
octal-constant:
0
octal-constant octal-digit
hexadecimal-constant:
hexadecimal-prefix hexadecimal-digit
hexadecimal-constant hexadecimal-digit
hexadecimal-prefix: один из следующих символов:
0x 0X
nonzero-digit: одна из указанных ниже
123456789
octal-digit: одна из указанных ниже
01234567
hexadecimal-digit: одна из указанных ниже
0123456789
abcdef
ABCDEF
integer-suffix:
unsigned-suffix long-suffixopt
unsigned-suffix long-long-suffix
unsigned-suffix 64-bit-integer-suffix
long-suffix unsigned-suffixopt
long-long-suffix unsigned-suffixopt
64-bit-integer-suffix
unsigned-suffix: one of
uU
long-suffix: one of
lL
long-long-suffix: один из следующих символов:
ll LL
64-bit-integer-suffix: один из следующих символов:
i64 I64
Суффиксы i64 и I64 используются только в системах Майкрософт.

Целые константы имеют положительное значение, если перед ними не указан знак "минус" ( - ). Знак
"минус" интерпретируется как унарный арифметический оператор изменения знака. (Сведения об этом
операторе см. в статье Unary Arithmetic Operators (Унарные арифметические операторы).

Если целая константа начинается с символов 0x или 0X , она является шестнадцатеричной. Если константа
начинается с цифры 0 , она восьмеричная. В противном случае считается, что она десятичная.

Следующие целочисленные константы эквивалентны:

28
0x1C /* = Hexadecimal representation for decimal 28 */
034 /* = Octal representation for decimal 28 */

Пробельные символы между цифрами целой константы не допускаются. В следующих примерах показаны
некоторые допустимые десятичные, восьмеричные и шестнадцатеричные константы.

/* Decimal Constants */
int dec_int = 28;
unsigned dec_uint = 4000000024u;
long dec_long = 2000000022l;
unsigned long dec_ulong = 4000000000ul;
long long dec_llong = 9000000000LL;
unsigned long long dec_ullong = 900000000001ull;
__int64 dec_i64 = 9000000000002I64;
unsigned __int64 dec_ui64 = 90000000000004ui64;

/* Octal Constants */
int oct_int = 024;
unsigned oct_uint = 04000000024u;
long oct_long = 02000000022l;
unsigned long oct_ulong = 04000000000UL;
long long oct_llong = 044000000000000ll;
unsigned long long oct_ullong = 044400000000000001Ull;
__int64 oct_i64 = 04444000000000000002i64;
unsigned __int64 oct_ui64 = 04444000000000000004uI64;

/* Hexadecimal Constants */
int hex_int = 0x2a;
unsigned hex_uint = 0XA0000024u;
long hex_long = 0x20000022l;
unsigned long hex_ulong = 0XA0000021uL;
long long hex_llong = 0x8a000000000000ll;
unsigned long long hex_ullong = 0x8A40000000000010uLL;
__int64 hex_i64 = 0x4a44000000000020I64;
unsigned __int64 hex_ui64 = 0x8a44000000000040Ui64;

См. также
Константы в C
Целочисленные типы
13.10.2020 • 2 minutes to read • Edit Online

Всем целым константам присваивается тип на основе их значения и способа представления. Для любой
целой константы можно принудительно задать тип long , добавив букву l или L в конец константы; для
принудительного задания типа unsigned добавьте в конец значения букву u или U . Следует избегать
использования буквы l в нижнем регистре, так как ее можно перепутать с цифрой 1. Ниже приведены
некоторые формы целых констант long :

/* Long decimal constants */


10L
79L

/* Long octal constants */


012L
0115L

/* Long hexadecimal constants */


0xaL or 0xAL
0X4fL or 0x4FL

/* Unsigned long decimal constant */


776745UL
778866LU

Тип, присваиваемый константе, зависит от значения, которое она представляет. Значение константы
должно находиться в диапазоне представимых значений для ее типа. Тип константы определяет , какие
преобразования выполняются при использовании константы в выражении или при добавлении знака
"минус" ( - ). В этом списке перечислены правила преобразования целых констант.
Для десятичной константы без суффикса используется тип int , long int или unsigned long int .
Константе присваивается первый из этих 3 типов, в котором возможно представление значения
константы.

Восьмеричным или шестнадцатеричным константам без суффиксов присваивается тип int ,


unsigned int , long int или unsigned long int в зависимости от размера константы.

Константам с суффиксом u или U присваивается тип unsigned int или unsigned long int в
зависимости от размера.

Константам с суффиксом l или L присваивается тип long int или unsigned long int в зависимости
от размера.

Константам с суффиксом u или U и l или L присваивается тип unsigned long int .

См. также
Целочисленные константы в C
Пределы целых чисел в C и C++
13.10.2020 • 3 minutes to read • Edit Online

Блок , относящийся только к системам Microsoft

Ограничения для целочисленных типов в C и C++ представлены в следующей таблице. Эти ограничения
заданы в стандартном файле заголовка C <limits.h> . Стандартный файл заголовка C++ <limits>
содержит <climits> , который включает в себя <limits.h> .

В Microsoft C также допускается объявление целочисленных переменных с указанием размера, которые


относятся к целочисленным типам с размером 8, 16, 32 или 64 бит. Дополнительные сведения о них см. в
статье Целочисленные типы с указанием размера.

Ограничения для целочисленных констант


КОНСТАНТА ЗНАЧЕНИЕ ЗНАЧЕНИЕ

CHAR_BIT Количество битов в наименьшей 8


переменной, которая не является
битовым полем.

SCHAR_MIN Минимальное значение для –128


переменной типа signed char .

SCHAR_MAX Максимальное значение для 127


переменной типа signed char .

UCHAR_MAX Максимальное значение для 255 (0xff)


переменной типа unsigned char .

CHAR_MIN Минимальное значение для –128 (или 0, если используется


переменной типа char . параметр /J)

CHAR_MAX Максимальное значение для –127 (или 255, если используется


переменной типа char . параметр /J)

MB_LEN_MAX Максимальное количество байтов в 5


многосимвольной константе.

SHRT_MIN Минимальное значение для -32768


переменной типа short .

SHRT_MAX Максимальное значение для 32767


переменной типа short .

USHRT_MAX Максимальное значение для 65 535 (0xffff)


переменной типа unsigned short .

INT_MIN Минимальное значение для -2147483647 - 1


переменной типа int .
КОНСТАНТА ЗНАЧЕНИЕ ЗНАЧЕНИЕ

INT_MAX Максимальное значение для 2147483647


переменной типа int .

UINT_MAX Максимальное значение для 4 294 967 295 (0xffffffff)


переменной типа unsigned int .

LONG_MIN Минимальное значение для -2147483647 - 1


переменной типа long .

LONG_MAX Максимальное значение для 2147483647


переменной типа long .

ULONG_MAX Максимальное значение для 4 294 967 295 (0xffffffff)


переменной типа unsigned long .

LLONG_MIN Минимальное значение для –9 223 372 036 854 775 807 – 1
переменной типа long long .

LLONG_MAX Максимальное значение для 9 223 372 036 854 775 807
переменной типа long long .

ULLONG_MAX Максимальное значение для 18 446 744 073 709 551 615
переменной типа (0xffffffffffffffff)
unsigned long long .

Если значение превышает максимально возможное представление целочисленного типа, компилятор


Microsoft выдает ошибку.
Завершение блока , относящегося только к системам Майкрософт

См. также
Целочисленные константы в C
Константы символов в C
15.05.2020 • 2 minutes to read • Edit Online

"Константа символа" создается путем заключения одного символа из набора представимых символов в
одинарные кавычки ( ' ' ). Константы символов используются для представления символов в кодировке
выполнения.

Синтаксис
character-constant: ' c-char-sequence '
L' c-char-sequence '
c-char-sequence: c-char
c-char-sequence c-char
c-char: Любой член исходной кодировки, кроме одинарной кавычки ( ' ), обратной косой черты ( \ ) и
символа новой строки

escape-sequence
escape-sequence: simple-escape-sequence
octal-escape-sequence
hexadecimal-escape-sequence
simple-escape-sequence: один из символов: \a \b \f \n \r \t \v
\' \" \\ \?
octal-escape-sequence: \ octal-digit
\ octal-digit octal-digit
\ octal-digit octal-digit octal-digit
hexadecimal-escape-sequence: \x hexadecimal-digit
hexadecimal-escape-sequence hexadecimal-digit

См. также
Константы в C
Символьные типы
13.10.2020 • 2 minutes to read • Edit Online

Целочисленная символьная константа, в начале которой не указана буква L , имеет тип int . Значением
целой символьной константы, содержащей один символ, является численное значение символа,
интерпретированное как целое число. Например, численное значение символа a равно 97 в десятичном
представлении и 61 в шестнадцатеричном представлении.

Синтаксически "расширенная символьная константа" представляет собой символьную константу с


префиксом в виде буквы L . Расширенная символьная константа имеет тип wchar_t — целочисленный тип,
определенный в файле заголовка STDDEF.H. Пример:

char schar = 'x'; /* A character constant */


wchar_t wchar = L'x'; /* A wide-character constant for
the same character */

Расширенные символьные константы имеют ширину 16 бит и указывают члены расширенной кодировки
выполнения. Они обеспечивают представление символов в алфавитах, слишком больших для
представления типом char . Дополнительные сведения о расширенных символах см. в статье
Многобайтовые и расширенные символы.

См. также
Константы символов в C
Набор символов исполнения
07.05.2020 • 2 minutes to read • Edit Online

Это содержимое часто называется "кодировкой выполнения". Кодировка выполнения не обязательно


совпадает с исходной кодировкой, используемой при написании программ на языке C. Кодировка
выполнения содержит все символы исходной кодировки, а также нуль-символ, символ новой строки, символ
возврата, символ горизонтальной табуляции, символ вертикальной табуляции, символ возврата каретки и
escape-последовательности. В других реализациях исходная кодировка и кодировка выполнения могут
различаться.

См. также
Константы символов в C
Escape-последовательность
15.05.2020 • 3 minutes to read • Edit Online

Сочетания символов, состоящих из обратной косой черты ( \ ), за которой следует буква или набор цифр,
называются escape-последовательностями. Для представления знака новой строки, одиночной кавычки
или некоторых других символов в символьной константе, необходимо использовать escape-
последовательности. Escape-последовательность рассматривается как один символ и, следовательно,
является допустимой символьной константой.

Escape-последовательности обычно используются для указания действий, например возврата каретки или
табуляции, на терминалах и принтерах. Они также используются для обозначения буквенных
представлений непечатаемых символов, а также символов, которые обычно имеют специальное значение,
например двойных кавычек ( " ). В следующей таблице перечислены escape-последовательности ANSI и
представляемые ими значения.

Обратите внимание, что вопросительный знак, перед которым стоит обратная косая черта ( \? ),
обозначает литерал вопросительного знака в случаях, когда данная последовательность символов может
быть ошибочно интерпретирована как триграф. Дополнительные сведения см. в разделе Триграфы.

Escape -последовательность
ESC A P E- ПОСЛЕДОВАТЕЛЬНОСТЬ ПРЕДСТАВЛЯЕТ

\a Звонок (предупреждение)

\b Backspace

\f Перевод страницы

\n Новая строка

\r Возврат каретки

\t Горизонтальная табуляция

\v Вертикальная табуляция

\' Одиночная кавычка

\" Двойная кавычка

\\ Обратная косая черта

\? Литерал вопросительного знака

\ ooo Символ ASCII в восьмеричной нотации

\x hh Символ ASCII в шестнадцатеричной нотации


ESC A P E- ПОСЛЕДОВАТЕЛЬНОСТЬ ПРЕДСТАВЛЯЕТ

\x hhhh Символ юникода в шестнадцатеричном формате, если


эта escape-последовательность используется в
многобайтовой знаковой константе или строковом
литерале юникода.

Например, WCHAR f = L'\x4e00' или


WCHAR b[] = L"The Chinese character for one is
\x4e00"
.

Блок , относящийся только к системам Microsoft

Если обратная косая черта предшествует символу, которого нет в таблице, компилятор не обрабатывает
неопределенный символ сам как символ. Например, escape-последовательность \c обрабатывается как
символ c .

Завершение блока , относящегося только к системам Майкрософт

Escape-последовательности позволяют отправлять неграфические управляющие символы на устройство


отображения. Например, символ ESC ( \033 ) часто используется в качестве первого символа команды
управления для терминала или принтера. Некоторые escape-последовательности используются только на
конкретных устройствах. Например, escape-последовательности вертикальной табуляции и перевода
страницы ( \v и \f ) не влияют на вывод данных на экране, но отвечают за соответствующие операции на
принтере.

Кроме того, обратную косую черту ( \ ) можно использовать как символ продолжения. Если сразу за
обратной косой чертой следует символ новой строки (эквивалентен нажатию клавиши ВОЗВРАТ ),
компилятор игнорирует эту последовательность и обрабатывает следующую строку как продолжение
предыдущей. Эта возможность используется в основном для определений препроцессора, длина которых
превышает одну строку. Пример:

#define assert(exp) \
( (exp) ? (void) 0:_assert( #exp, __FILE__, __LINE__ ) )

См. также
Константы символов в C
Спецификации восьмеричных и
шестнадцатеричных символов
13.10.2020 • 3 minutes to read • Edit Online

Последовательность \ ooo означает , что можно указать любой набор символов в кодировке ASCII в качестве
трехразрядного восьмеричного кода знака. Числовое значение восьмеричного целого числа указывает
значение требуемого символа или расширенного символа.

Аналогичным образом последовательность \x hhh позволяет указать любой символ в кодировке ASCII в
качестве шестнадцатеричного кода знака. Например, символ backspace (ASCII) можно представить как
обычную escape-последовательность C ( \b ), закодировать как восьмеричный код \010 или
шестнадцатеричный код \x008 .

В восьмеричной escape-последовательности можно использовать только цифры от 0 до 7. Длина


восьмеричной escape-последовательности не может превышать три цифры, и такие последовательности
заканчиваются на первом символе, который не является цифрой в восьмеричном формате. Хотя нет
необходимости использовать все три цифры, необходимо использовать по крайней мере одну. Например,
для символа backspace по таблице ASCII восьмеричное представление имеет вид \10 , а для буквы A — \101 .

Аналогичным образом, необходимо использовать хотя бы одну цифру для шестнадцатеричной escape-
последовательности, но можно опустить вторую и третью цифры. Следовательно, шестнадцатеричную
escape-последовательность для символа backspace можно указать как \x8 , \x08 или \x008 .
Значение восьмеричной или шестнадцатеричной escape-последовательности должно находиться в
диапазоне представимых значений для типа unsigned char для символьной константы и типа wchar_t для
расширенной символьной константы. Дополнительные сведения о расширенных символьных константах см.
в статье Многобайтовая кодировка и расширенные символы.

В отличие от восьмеричных escape-констант количество шестнадцатеричных цифр в escape-


последовательности не ограничено. Шестнадцатеричная escape-последовательность заканчивается на
первом символе, который не является цифрой в восьмеричном формате. Поскольку шестнадцатеричные
цифры включают буквы от a до f , убедитесь, что escape-последовательность заканчивается на
соответствующей цифре. Чтобы избежать путаницы, можно добавить определения восьмеричных или
шестнадцатеричных символов в определение макроса.

#define Bell '\x07'

В случае шестнадцатеричных значений можно разделить строку для четкого отображения правильного
значения.

"\xabc" /* one character */


"\xab" "c" /* two characters */

См. также
Константы символов в C
Строковые литералы в C
15.05.2020 • 2 minutes to read • Edit Online

"Строковый литерал" — это последовательность символов исходной кодировки, заключенных в двойные


кавычки ( " " ). Строковые литералы используются для представления последовательности символов,
которые вместе образуют строку, завершающуюся нуль-символом. Перед двухбайтовыми строковыми
литералами всегда должна ставиться буква L .

Синтаксис
string-literal:
" s-char-sequenceopt "
L" s-char-sequenceopt "
s-char-sequence:
s-char
s-char-sequence s-char
s-char:
любой член исходной кодировки, кроме двойной кавычки ("), обратной косой черты (\) и символа новой
строки

escape-sequence

Примечания
В приведенном ниже примере показан простой строковый литерал.

char *amessage = "This is a string literal.";

В строковых литералах допустимо использовать все коды, перечисленные в таблице escape-


последовательностей. Для представления в строковом литерале двойной кавычки следует использовать
escape-последовательность \" . Одинарная кавычка ( ' ) может быть представлена без escape-
последовательности. Если в строке имеется обратная косая черта ( \ ), после нее должна следовать вторая
такая черта ( \\ ). Если обратная косая черта находится в конце строки, она всегда интерпретируется как
символ объединения строк.

См. также
Элементы языка C
Тип для строковых литералов
13.10.2020 • 2 minutes to read • Edit Online

Строковые литералы имеют тип массива char (т. е., char[ ] ). (Строки расширенных символов имеют тип
массива wchar_t (т. е., wchar_t[ ] ).) Это означает , что строка является массивом с элементами типа char .
Число элементов в массиве равно числу символов в строке плюс один дополнительный элемент для
завершающего символа null.

См. также
Строковые литералы в C
Хранение строковых литералов
07.05.2020 • 2 minutes to read • Edit Online

Символы строкового литерала хранятся по порядку в смежных адресах памяти. Любая escape-
последовательность (например, \\ или \" ) внутри строкового литерала считается одним символом. В
каждый строковый литерал автоматически добавляется нуль-символ (представленный escape-
последовательностью \0 ), который обозначает его конец. (Это происходит на этапе преобразования 7.)
Обратите внимание, что компилятор не может сохранить две одинаковые строки отдельно с разными
адресами. Ключ /GF указывает , что компилятор должен сохранять в исполняемом файле только одну копию
одинаковых строк.

Примечания
Блок , относящийся только к системам Microsoft

Строки имеют статическую длительность хранения. Дополнительные сведения о длительности хранения


см. в разделе Классы хранения в C.

Завершение блока , относящегося только к системам Майкрософт

См. также
Строковые литералы в C
Объединение строковых литералов
07.05.2020 • 3 minutes to read • Edit Online

Для создания строкового литерала, занимающего более одной строки, можно объединить две строки. Для
этого следует ввести обратную косую черту и нажать клавишу ВВОД. Обратная косая черта указывает
компилятору игнорировать следующий символ новой строки. Например, строковый литерал

"Long strings can be bro\


ken into two or more pieces."

идентичен строке

"Long strings can be broken into two or more pieces."

Вместо использования обратной косой черты с последующим символом новой строки для ввода строк,
длина которых превышает одну строку, можно использовать объединение строк.

Чтобы принудительно создать новую строку внутри строкового литерала, следует ввести escape-
последовательность новой строки ( \n ) в том месте строки, где требуется сделать разрыв:

"Enter a number between 1 and 100\nOr press Return"

Поскольку строки могут начинаться в любом столбце исходного кода и длинные строки можно продолжать
в любом столбце последующей строки, строки можно позиционировать для повышения удобства чтения
исходного кода. В любом случае их представление на экране при выводе результата не затрагивается.
Пример:

printf_s ( "This is the first half of the string, "


"this is the second half ") ;

Так как каждая часть строки заключается в двойные кавычки, части объединяются и результат
отображается в виде одной строки. Такое объединение происходит в соответствии с последовательностью
событий во время компиляции, определенной этапами преобразования.

"This is the first half of the string, this is the second half"

Указатель на строку, инициализированный как два разных строковых литерала, разделенных только
пробелом, хранится в виде одной строки (указатели рассматриваются в разделе Объявления указателей).
При правильном выполнении ссылки (см. следующий пример) результат идентичен результату
предыдущего примера.

char *string = "This is the first half of the string, "


"this is the second half";

printf_s( "%s" , string ) ;

На шестом этапе преобразования последовательности многобайтовых символов, заданные любой


последовательностью соседних строковых литералов или соседних двухбайтовых строковых литералов,
объединяются в одну последовательность многобайтовых символов. Поэтому не следует разрабатывать
программы, допускающие изменение строковых литералов во время выполнения. В стандарте ANSI C
указывается, что результат изменения строки не определен.

См. также
Строковые литералы в C
Максимальная длина строки
07.05.2020 • 2 minutes to read • Edit Online

Блок , относящийся только к системам Microsoft

В режиме совместимости с ANSI требуется, чтобы компилятор принимал до 509 символов в строковом
литерале после объединения. Максимальная допустимая длина строкового литерала в Microsoft C —
приблизительно 2048 байтов. Однако если строковый литерал состоит из двух частей, заключенных в
двойные кавычки, препроцессор объединяет эти части в одну строку, и для каждой объединенной строки
добавляет дополнительный байт к общему количеству байтов.

Например, предположим, что строка состоит из 40 строк с 50 символами в каждой строке (2000 символов) и
одной строки с 7 символами и что каждая строка заключена в двойные кавычки. Это значит , что
добавляется до 2007 байтов плюс один байт для завершающего нуль-символа, то есть всего 2008 байтов. В
объединении дополнительный символ добавляется для каждой из первых 40 строк. В результате мы
получаем 2048 байтов. Обратите внимание, что если вместо двойных кавычек используются продолжения
строк (\), препроцессор не добавляет дополнительный символ для каждой строки.

Хотя отдельные строки в кавычках не могут быть длиннее 2048 байтов, объединив строки, можно создать
строковый литерал, состоящий приблизительно из 65535 байтов.

Завершение блока , относящегося только к системам Майкрософт

См. также
Строковые литералы в C
Знаки препинания и специальные символы
07.05.2020 • 2 minutes to read • Edit Online

Знаки пунктуации и специальные символы в наборе символов языка C имеют различные применения, от
организации текста программы до определения задач, выполняемых компилятором или скомпилированной
программой. Эти знаки не определяют операции, подлежащие выполнению. Некоторые знаки пунктуации
также являются операторами (см. статью Операторы в C). Компилятор определяет их использование в
зависимости от контекста.

Синтаксис
punctuator : один из символов: [ ] ( ) { } * , : = ; ... #
Эти символы имеют специальное значение в языке C. Их применение описывается в настоящем руководстве.
Знак решетки ( # ) может использоваться только в директивах препроцессора.

См. также
Элементы языка C
Структура программы
07.05.2020 • 2 minutes to read • Edit Online

В этом разделе приводится обзор программ на языке C и описание их выполнения. Также здесь приводятся
термины и функции, важные для понимания программ и компонентов на языке C. В разделе
рассматриваются следующие темы.

Файлы с исходным кодом и исходные программы

Функция main и выполнение программ

Анализ аргументов командной строки

Время существования, область, видимость и компоновка

Пространства имен

Поскольку в этом разделе приводятся общие сведения, в указанных выше темах представлен лишь вводный
материал. Для получения дополнительных сведений см. соответствующие перекрестные ссылки.

См. также
Справочник по языку C
Файлы с исходным кодом и исходные программы
15.05.2020 • 2 minutes to read • Edit Online

Исходную программу можно разделить на один или несколько исходных файлов. Когда такие файлы
передаются компилятору, они называются блоками трансляции.

Синтаксис
translation-unit:
external-declaration
translation-unit external-declaration
external-declaration:
function-definition
declaration
В статье Общие сведения об объявлениях описывается синтаксис нетерминала declaration , а в
справочнике по препроцессору поясняется, как происходит обработка записи преобразования.

NOTE
Описание соглашений о синтаксисе ANSI вы найдете во введении к статье Общие сведения о синтаксисе языка C.

Компонентами блока трансляции являются внешние объявления, которые включают в себя определения
функций и объявления идентификаторов. Эти объявления и определения могут находиться в исходных
файлах, файлах заголовков, библиотеках и других файлах, которые необходимы программе. Чтобы создать
программу, необходимо скомпилировать каждый блок трансляции и скомпоновать полученный объектный
файл.

Исходная программа языка C представляет собой набор директив, директив pragma, объявлений,
определений, блоков операторов и функций. Для того чтобы все они были допустимыми компонентами
программы на языке Microsoft C, они должны иметь синтаксис, описанный в настоящей книге. При этом они
могут находиться в программе в любом порядке (в пределах описанных здесь правил). Однако от
расположения этих компонентов в программе зависит то, каким образом в программе будут
использоваться переменные и функции. (Дополнительные сведения см. в статье Время существования,
область, видимость и компоновка.)

Исходные файлы не должны содержать исполняемых операторов. К примеру, в один исходный файл
можно поместить все определения переменных, а затем в другом исходном файле, в котором эти
переменные используются, объявить ссылки на них. Этот метод позволяет легко находить и при
необходимости изменять определения. По этой же причине константы и макросы часто организуются в
отдельные файлы — так называемые включаемые файлы, или файлы заголовка. По мере необходимости на
них можно ссылаться из исходных файлов. Сведения о макросах и включаемых файлах см. в справочнике
по препроцессору.

См. также
Структура программы
Директивы препроцессору
06.05.2020 • 2 minutes to read • Edit Online

Директива указывает препроцессору C выполнять определенное действие в тексте программы перед


компиляцией. Директивы препроцессора полностью описаны в справочнике по препроцессору. В
следующем примере используется директива препроцессора #define .

#define MAX 100

Этот оператор указывает компилятору заменять каждое вхождение MAX на 100 перед компиляцией. Ниже
перечислены директивы препроцессора компилятора C.

#DEF IN E #EN DIF #IF DEF #L IN E

#elif #error #ifndef #pragma

#else #if #include #undef

См. также
Файлы с исходным кодом и исходные программы
Прагмы C
13.10.2020 • 2 minutes to read • Edit Online

Блок , относящийся только к системам Microsoft

Директива pragma указывает компилятору выполнить определенное действие во время компиляции.


Директивы pragma зависят от компилятора. Например, чтобы задать оптимизации для выполнения в
программе, можно использовать директиву pragma optimize . Ниже перечислены директивы pragma
Microsoft C.
alloc_text
auto_inline
bss_seg
check_stack
code_seg
comment
component
const_seg
data_seg

deprecated
detect_mismatch
fenv_access
float_control
fp_contract
function
hdrstop
include_alias
inline_depth

inline_recursion
intrinsic
make_public
managed
message
omp
once
optimize
pack

pop_macro
push_macro
region , endregion
runtime_checks
section
setlocale
strict_gs_check
unmanaged
warning
Описание директив pragma для компилятора Microsoft C см. в статье Директивы Pragma и ключевое слово
__Pragma .
Завершение блока , относящегося только к системам Майкрософт

См. также
Файлы с исходным кодом и исходные программы
Объявления и определения в C
07.05.2020 • 2 minutes to read • Edit Online

Объявление устанавливает связь между указанной переменной, функцией или типом и их атрибутами. В
статье Общие сведения об объявлениях приводится синтаксис ANSI для нетерминального элемента
declaration . В объявлении также определяется, где и когда возможен доступ к идентификатору
("компоновка" идентификатора). Дополнительные сведения о компоновке см. в статье Время существования,
область, видимость и компоновка.

Определение переменной устанавливает те же связи, что и объявление, но также приводит к выделению


памяти для переменной.

Например, функции main , find и count и переменные var и val определяются в одном исходном файле
в следующем порядке:

int main() {}

int var = 0;
double val[MAXVAL];
char find( fileptr ) {}
int count( double f ) {}

Переменные var и val могут использоваться в функциях find и count ; никакие дополнительные
объявления не требуются. Однако в функции main эти имена не видны (доступ к ним невозможен).

См. также
Файлы с исходным кодом и исходные программы
Объявления и определения функций
07.05.2020 • 2 minutes to read • Edit Online

Прототипы функций устанавливают имя функции, тип возвращаемого ею значения, а также тип и число ее
формальных параметров. Определение функции содержит тело функции.

Примечания
Объявления функции и переменных могут находиться внутри или вне определения функции. Считается, что
любое объявление, сделанное внутри определения функции, находится на "внутреннем", или "локальном",
уровне, а объявление, расположенное вне всех определений функций, находится на внешнем, глобальном
уровне или на уровне области видимости файла. Определения переменных, подобно объявлениям, могут
находиться на внутреннем (в определении функции) или внешнем (вне всех определений функций) уровне.
Определения функций всегда находятся на внешнем уровне. Подробнее определения функций
рассматриваются в статье Определения функций. Прототипы функций описаны в статье Прототипы
функций.

См. также
Файлы с исходным кодом и исходные программы
Blocks
07.05.2020 • 2 minutes to read • Edit Online

Последовательность объявлений, определений и операторов, заключенная в фигурные скобки ( { } ),


называется "блоком". Существует два типа блоков в С. «Составной оператор» оператор, состоящие из одной
или нескольких инструкций (см. составной оператор), один тип блока. Второй тип блоков — определение
функции — состоит из составного оператора (тело функции) и связанного заголовка функции (имя функции,
тип возвращаемого значения и формальные параметры). Блок, находящийся в другом блоке, называется
вложенным.

Обратите внимание, что хотя все составные операторы заключены в фигурные скобки, не все элементы,
заключенные в фигурные скобки, являются составным оператором. Например, несмотря на то что
спецификации элементов массива, структуры или перечисления могут быть заключены в фигурные скобки,
они не являются составными операторами.

См. также
Файлы с исходным кодом и исходные программы
Пример программы
13.10.2020 • 3 minutes to read • Edit Online

Следующая исходная программа на языке C состоит из двух файлов исходного кода. В ней показаны
различные объявления и определения, возможные в программе на языке C. В последующих разделах этого
документа описывается, как создавать такие объявления, определения и инициализации, и как использовать
ключевые слова C, например static и extern . Функция printf объявлена в файле заголовка C STDIO.H.

Предполагается, что функции main и max находятся в разных файлах, а выполнение программы
начинается с функции main . Перед функцией main не выполняются никакие явные пользовательские
функции.

/*****************************************************************
FILE1.C - main function
*****************************************************************/

#define ONE 1
#define TWO 2
#define THREE 3
#include <stdio.h>

int a = 1; // Defining declarations


int b = 2; // of external variables

extern int max( int a, int b ); // Function prototype

int main() // Function definition


{ // for main function
int c; // Definitions for
int d; // two uninitialized
// local variables

extern int u; // Referencing declaration


// of external variable
// defined elsewhere
static int v; // Definition of variable
// with continuous lifetime

int w = ONE, x = TWO, y = THREE;


int z = 0;

z = max( x, y ); // Executable statements


w = max( z, w );
printf_s( "%d %d\n", z, w );
return 0;
}

/****************************************************************
FILE2.C - definition of max function
****************************************************************/

int max( int a, int b ) // Note formal parameters are


// included in function header
{
if( a > b )
return( a );
else
return( b );
}
Файл FILE1.C содержит прототип для функции max . Объявления этого типа иногда называются
"опережающими", поскольку функция объявляется до ее использования. Определение функции main
содержит вызовы функции max .

Строки, начинающиеся с #define , представляют собой директивы препроцессора. В соответствии с этими


директивами препроцессор заменяет идентификаторы ONE , TWO и THREE в файле FILE1. C цифрами 1 , 2 и
3 , соответственно. Однако эти директивы не применяются к файлу FILE2.C, который компилируется
отдельно, а затем компонуется с файлом FILE1.C. Строка, начинающаяся с #include , содержит указание
компилятору на включение файла STDIO.H, содержащего прототип для функции printf . Директивы
препроцессора рассматриваются в справочнике по препроцессору.

В файле FILE1.C используются определяющие объявления для инициализации глобальных переменных a и


b . Локальные переменные c и d объявлены, но не инициализированы. Для всех этих переменных
выделена память. Статические и внешние переменные, u и v , автоматически инициализируются
значением 0. Поэтому при объявлении значимые значения содержат только переменные a , b , u и v ,
которые явно или неявно инициализированы. Файл FILE2.C содержит определение функции max . Это
определение соответствует вызовам функции max из файла FILE1.C.

Время существования и область видимости идентификаторов рассматриваются в статье Время


существования, область, видимость и компоновка. Дополнительные сведения о функциях вы найдете в
разделе, посвященном функциям.

См. также
Файлы с исходным кодом и исходные программы
Функция main и выполнение программ
13.10.2020 • 3 minutes to read • Edit Online

Все программы, написанные на языке C, содержат основную функцию, которая должна иметь имя main .
Если код соответствует модели программирования Юникода, можно использовать версию функции
main для многобайтовых символов с именем wmain . Функция main является начальной точкой для
выполнения программы. Она обычно управляет выполнением программы, вызывая другие ее функции. Как
правило, выполнение программы завершается в конце функции main , но по разным причинам это может
случиться и в других местах программы. Иногда (возможно, при обнаружении некоторой ошибки) может
потребоваться принудительно завершить программу. Для этого используйте функцию exit . Сведения о
функции exit и пример ее использования см. в Справочнике по библиотеке времени выполнения.

Синтаксис
main( int argc, char *argv[ ], char *envp[ ] )

Примечания
Функции в исходном коде программы выполняют одну или несколько конкретных задач. Функция main
может вызывать эти функции для выполнения соответствующих задач. Когда функция main вызывает
другую функцию, она передает ей управление выполнением, и работа программы продолжается с первого
оператора вызываемой функции. Вызываемая функция возвращает управление функции main , когда
выполняется оператор return или достигается конец этой функции.

Для любой функции, включая функцию main , можно объявить наличие параметров. Термин "параметр"
или "формальный параметр" относится к идентификатору, получающему значение, передаваемое
функции. Сведения о передаче аргументов в качестве параметров вы найдете в статье Параметры. Когда
одна функция вызывает другую, вызываемая функция получает значения своих параметров от
вызывающей функции. Эти значения называются аргументами. Для функции main можно объявить
формальные параметры, и тогда она будет принимать аргументы из командной строки в следующем
формате.

Если в функцию main передаются параметры, они традиционно именуются argc и argv , хотя компилятор
C не обязывает использовать именно эти имена. Типы для параметров argc и argv определяются языком
C. Если в функцию main передается третий параметр, он по традиции называется envp . В приведенных
ниже в данном разделе примерах описывается использование этих трех параметров для доступа к
аргументам командной строки. Эти параметры объясняются в следующих разделах.

Описание версии main для расширенных символов см. в статье Использование wmain .

См. также
Функция main и аргументы командной строки (C++)
Анализ аргументов командной строки C
Использование wmain
07.05.2020 • 2 minutes to read • Edit Online

Блок , относящийся только к системам Microsoft

В модели программирования Юникода можно определить версию функции main для расширенных
символов. Используйте wmain вместо main , если вам нужен переносимый код, соблюдающий модель
программирования Юникода.

Синтаксис
wmain( int argc, wchar_t *argv[ ], wchar_t *envp[ ] )

Примечания
Формальные параметры для функции wmain объявляются в том же формате, что и для функции main .
Затем можно передать в качестве аргументов "широкие" символы и указатель среды кодировки Юникод
(необязательно) в программу. Параметры argv и envp для функции wmain относятся к типу wchar_t* .
Пример:

Если программа использует функцию main , окружение многобайтовой кодировки создается библиотекой
времени выполнения при запуске программы. Копия среды для Юникода создается только при
необходимости (например, для вызова функции _wgetenv или _wputenv ). При первом вызове _wputenv или
_wgetenv , если среда многобайтовой кодировки (MBCS) уже существует , создается соответствующая среда
широкосимвольной строки, на которую затем указывает глобальная переменная _wenviron ,
представляющая собой широкосимвольную версию глобальной переменной _environ . В этот момент две
копии среды (для многобайтовой кодировки и Юникода) существуют одновременно и поддерживаются
операционной системой в течение всего срока жизни программы.

Аналогичным образом, если программа использует функцию wmain , при запуске программы создается
окружение расширенных символов и ссылка на него сохраняется в глобальной переменной _wenviron .
Среда многобайтовой кодировки MBCS (ASCII) создается при первом вызове функции _putenv или getenv ,
и на нее указывает глобальная переменная _environ .

Дополнительные сведения об окружении многобайтовой кодировки MBCS см. в разделе


Интернационализация в справочнике по библиотеке времени выполнения.

Завершение блока , относящегося только к системам Майкрософт

См. также
Функция main и выполнение программ
Описание аргумента
13.10.2020 • 3 minutes to read • Edit Online

Параметр argc в функциях main и wmain выражается целым числом и обозначает количество аргументов,
переданных в программу из командной строки. Поскольку имя программы считается аргументом, значение
argc по крайней мере равно единице.

Примечания
Параметр argv является массивом указателей на строки, завершающиеся значением NULL, который
представляет аргументы программы. Каждый элемент массива указывает на строковое представление
аргумента, переданного в main (или wmain ). (Дополнительные сведения о массивах см. в разделе
Объявления массивов.) Параметр argv можно объявить как массив указателей на тип char ( char *argv[] )
или как указатель на указатели на тип char ( char **argv ). Параметр argv в wmain можно объявить как
массив указателей на тип wchar_t ( wchar_t *argv[] ) или как указатель на указатели на тип wchar_t (
wchar_t **argv ).
По соглашению параметр argv [0] содержит команду, которая использовалась для вызова программы.
Однако процесс можно инициализировать с помощью CreateProcess, а если указаны и первый, и второй
аргументы ( lpApplicationName и lpCommandLine ), то argv [0] не будет содержать имени исполняемого файла.
Чтобы гарантированно получить имя исполняемого файла, используйте GetModuleFileName.

Последний указатель ( argv[argc] ) имеет значение NULL . (Альтернативный метод получения сведений о
переменной среды см. в разделе getenvСправочника по библиотеке времени выполнения.)

Блок , относящийся только к системам Microsoft

Параметр envp является указателем на массив строк, завершающихся значением NULL, которые
представляют значения, заданные в переменных среды пользователя. Параметр envp можно объявить как
массив указателей на тип char ( char *envp[] ) или как указатель на указатели на тип char ( char **envp ).
Параметр envp в функции wmain можно объявить как массив указателей на wchar_t ( wchar_t *envp[] ) или
как указатель на указатели на wchar_t ( wchar_t **envp ). Конец массива определяется указателем NULL *.
Обратите внимание, что передаваемый в main или wmain блок окружения является "замороженной"
копией текущего окружения. Если окружение будет позднее изменена путем вызова _putenv или _wputenv ,
изменится только текущее окружение (которое возвращают getenv / _wgetenv и переменные _environ или
_wenviron ); но не блок, на который указывает envp . Параметр envp совместим с ANSI в C, но не в C++.

Завершение блока , относящегося только к системам Майкрософт

См. также
Функция main и выполнение программ
Расширение аргументов заполнителей
07.05.2020 • 2 minutes to read • Edit Online

Блок , относящийся только к системам Microsoft

При выполнении программы на языке C можно использовать любой из двух подстановочных знаков, вопрос
(?) или звездочку (*), для задания аргументов имени файла и пути в командной строке.
По умолчанию подстановочные знаки в аргументах командной строки не разворачиваются. Вы можете
заменить обычную процедуру загрузки вектора аргументов argv на версию, которая разворачивает
подстановочные знаки, используя компоновку с файлом setargv.obj или wsetargv.obj. Если программа
использует функцию main , скомпонуйте ее с файлом setargv.obj. Если программа использует функцию
wmain , скомпонуйте ее с файлом wsetargv.obj. Они оба реализуют эквивалентное поведение.

Чтобы скомпоновать программу с файлом setargv.obj или wsetargv.obj, используйте параметр /link . Пример:

cl example.c /link setargv.obj


Подстановочные знаки разворачиваются так же, как команды операционной системы. (См.
ознакомительные сведения о подстановочных знаках в руководстве пользователя вашей ОС ).

Завершение блока , относящегося только к системам Майкрософт

См. также
Параметры ссылок
Функция main и выполнение программ
Анализ аргументов командной строки C
07.05.2020 • 3 minutes to read • Edit Online

Блок , относящийся только к системам Microsoft

В коде запуска Microsoft C используются следующие правила при обработке аргументов, вводимых в
командной строке операционной системы.

Аргументы разделяются пробелами (пробел или табуляция).

Строка, заключенная в двойные прямые кавычки, обрабатывается как один аргумент , независимо от
пробельных символов, которые могут в ней присутствовать. Строку в кавычках можно встроить в
аргумент. Обратите внимание, что символ каретки ( ^ ) не воспринимается как escape-символ или
разделитель.

Символ двойной кавычки после обратной косой черты ( \" ) обрабатывается как литеральный символ
двойной кавычки ( " ).

Символы обратной косой черты обрабатываются буквально, если только им не предшествует


двойная кавычка.

Если двойная кавычка стоит после четного числа символов обратной косой черты, в массив argv
помещается по одному символу обратной косой черты ( \ ) для каждой пары символов обратной
косой черты ( \\ ), а двойная кавычка ( " ) обрабатывается как разделитель строк.

Если двойная кавычка стоит после нечетного числа символов обратной косой черты, в массив argv
помещается по одному символу обратной косой черты ( \ ) для каждой пары символов обратной
косой черты ( \\ ), а символ двойной кавычки с оставшимся символом обратной косой черты
интерпретируется как escape-последовательность, в результате чего в массив argv помещается
литеральный символ двойной кавычки ( " ).

В следующем списке, иллюстрирующем указанные выше правила, показаны результаты, передаваемые в


массив argv для нескольких примеров аргументов командной строки. Выходные данные, представленный
во втором, третьем и четвертом столбцах, получены из программы ARGS.C, приведенной после списка.

ДАННЫЕ В КОМАНДНОЙ
СТРОКЕ A RGV[ 1] A RGV[ 2] A RGV[ 3]

"a b c" d e a b c d e

"ab\"c" "\\" d ab"c \ d

a\\\b d"e f"g h a\\\b de fg h

a\\\"b c d a\"b c d

a\\\\"b c" d e a\\b c d e

Пример
Код
// Parsing_C_Commandline_args.c
// ARGS.C illustrates the following variables used for accessing
// command-line arguments and environment variables:
// argc argv envp
//

#include <stdio.h>

int main( int argc, // Number of strings in array argv


char *argv[], // Array of command-line argument strings
char **envp ) // Array of environment variable strings
{
int count;

// Display each command-line argument.


printf_s( "\nCommand-line arguments:\n" );
for( count = 0; count < argc; count++ )
printf_s( " argv[%d] %s\n", count, argv[count] );

// Display each environment variable.


printf_s( "\nEnvironment variables:\n" );
while( *envp != NULL )
printf_s( " %s\n", *(envp++) );

return;
}

Комментарии
Ниже приведен один пример данных, выводимых этой программой:

Command-line arguments:
argv[0] C:\MSC\TEST.EXE

Environment variables:
COMSPEC=C:\NT\SYSTEM32\CMD.EXE

PATH=c:\nt;c:\binb;c:\binr;c:\nt\system32;c:\word;c:\help;c:\msc;c:\;
PROMPT=[$p]
TEMP=c:\tmp
TMP=c:\tmp
EDITORS=c:\binr
WINDIR=c:\nt

Завершение блока , относящегося только к системам Майкрософт

См. также
Функция main и выполнение программ
Настройка обработки командной строки C
07.05.2020 • 2 minutes to read • Edit Online

Если программа не принимает аргументы командной строки, можно сохранить небольшой объем
пространства, подавив использование подпрограммы библиотеки, выполняющей обработку командной
строки. Эта подпрограмма называется _setargv (или _wsetargv в окружении расширенных символов), как
описано в статье Wildcard Expansion (Развертывание подстановочных знаков). Чтобы подавить ее
использование, в файле, содержащем функцию main , определите подпрограмму с именем _setargv (или
_wsetargv в окружении расширенных символов), которая не выполняет никаких действий. Тогда для
вызовов _setargv и _wsetargv будет использоваться ваше определение _setargv или _wsetargv , а версия
из библиотеки загружаться не будет.

Аналогичным образом, если вам не нужно обращаться к таблице окружения с помощью аргумента envp , вы
можете предоставить собственную пустую подпрограмму вместо подпрограммы обработки окружения
_setenvp (или _wsetenvp ).
Если программа вызывает подпрограммы из семейства _spawn или _exec , определенные в библиотеке
времени выполнения C, подпрограмму обработки окружения подавлять не следует , поскольку она
используется для передачи окружения из вызывающего процесса в новый процесс.

См. также
Функция main и выполнение программ
Время жизни, область, видимость и компоновка
07.05.2020 • 2 minutes to read • Edit Online

Чтобы понимать, как работает программа на языке C, необходимо знать правила, определяющие
использование переменных и функций в программе. Для понимания этих правил исключительно важны
следующие понятия:

Время существования

Scope and visibility (Область и видимость)


Компоновка

См. также
Структура программы
Время существования
13.10.2020 • 3 minutes to read • Edit Online

"Время жизни" представляет собой период во время выполнения программы, в течение которого
существует переменная или функция. Время жизни идентификатора определяется длительностью его
хранения.

Идентификатор, объявленный описателем класса хранения типа static , имеет статическую длительность
хранения. Идентификаторы со статической длительностью хранения (также называемые "глобальными")
имеют выделенную память и определенное значение в течение всего времени выполнения программы.
Выделение памяти и инициализация хранящегося значения идентификатора производятся только один раз
перед началом работы программы. Идентификатор, объявленный с внешней или внутренней компоновкой,
также имеет статическую длительность хранения (см. статью Компоновка).

Идентификатор, объявленный без описателя класса хранения типа static , имеет автоматическую
длительность хранения, если он объявлен внутри функции. Идентификатор с автоматической
длительностью хранения ("локальный идентификатор") имеет выделенную память и определенное
значение только внутри блока, в котором он определен или объявлен. Автоматическому идентификатору
выделяется новая память при каждом входе программы в соответствующий блок; при выходе программы из
этого блока память (и значение) идентификатора освобождается. Идентификаторы, объявленные в
функции без компоновки, также имеют автоматическую длительность хранения.

Следующие правила определяют , имеет ли идентификатор глобальное (статическое) или локальное


(автоматическое) время жизни:
Все функции имеют статическое время жизни. Поэтому они существуют в течение всего времени
выполнения программы. Идентификаторы, объявленные на внешнем уровне (т. е., вне всех блоков в
программе на одном уровне определений функций), всегда имеют глобальное (статическое) время
жизни.

Если локальная переменная имеет инициализатор, она инициализируется при каждом создании (если
она не объявлена как static ). Параметры функции также имеют локальное время жизни. Для
идентификатора можно определить глобальное время существования в пределах блока, включив в
его объявление описатель класса хранения типа static . Если переменная объявлена как static ,
она сохраняет свое значение между последовательными входами в блок.

Хотя идентификатор с глобальным временем существования существует в течение всего времени


выполнения исходной программы (например, внешне объявленная переменная или локальная переменная,
объявленная с ключевым словом static ), он может быть доступен не во всех частях программы. Сведения
о видимости приводятся в статье Область и видимость, а нетерминальный описатель storage-class-specifier
рассматривается в статье Классы хранения в C.

Память может выделяться по мере необходимости (динамически), если создается с помощью специальных
библиотечных процедур, таких как malloc . Поскольку динамическое выделение памяти использует
библиотечные процедуры, оно не считается составной частью языка. См. описание функции malloc в
справочнике по библиотеке времени выполнения.

См. также
Время жизни, область, видимость и компоновка
Область и видимость
13.10.2020 • 3 minutes to read • Edit Online

Видимость идентификатора определяет части программы, в которых можно сослаться на идентификатор,


то есть ее область. Идентификатор является видимым (т. е. его можно использовать) только в частях
программы, входящих в ее область, которая может быть ограничена (в порядке повышение количества
ограничений) файлом, функцией, блоком или прототипом функции, в котором она отображается. Область
идентификатора — это часть программы, в которой можно использовать имя. В некоторых случаях она
называется лексической областью. Существует четыре типа области: функция, файл, блок и прототип
функции.

Все идентификаторы за исключением меток имеют область, определенную уровнем объявления.


Видимость идентификаторов внутри программы регулируется следующими правилами для каждого типа
области.

Область видимости файла. Декларатор или описатель типа идентификатора с областью видимости файла
отображается вне любого блока или списка параметров и доступен из любого места записи
преобразования после объявления. Имена идентификаторов с областью видимости файла часто
называются глобальными или внешними. Область глобального идентификатора начинается с момента его
определения или объявления и заканчивается в конце записи преобразования.

Область видимости функции. Метка — это единственный тип идентификатора, который имеет область
видимости функции. Метка объявляется неявно путем использования в операторе. Имена меток должны
быть уникальными внутри функции. (Дополнительные сведения о метках и именах меток см. в статье
Оператор goto и помеченные операторы.)

Область видимости блока. Декларатор или описатель типа идентификатора с областью видимости блока
отображаются внутри блока или в списке объявлений формальных параметров в определении функции.
Он является видимым только с момента его определения или объявления до конца блока, содержащего
объявление или определение. Его область ограничена данным блоком и любыми блоками, которые
является вложенными по отношению к данному блоку, и заканчивается на фигурной скобке, закрывающей
связанный блок. Эти идентификаторы иногда называются локальными переменными.

Область видимости прототипа функции. Декларатор или описатель типа идентификатора с областью
видимости прототипа функции отображается в списке объявлений параметров в прототипе функции (не
является частью объявления функции). Эта область заканчивается в конце декларатора функции.

Описание соответствующих объявлений, используемых для отображения переменных в других исходных


файлах, см. в статье Классы хранения в C. Однако переменные и функции, объявленные на внешнем уровне
с описателем класса хранения static , доступны только в том исходном файле, в котором они определены.
Все остальные функции видимы глобально.

См. также
Время жизни, область, видимость и компоновка
Сводка времени существования и видимости
13.10.2020 • 2 minutes to read • Edit Online

В следующей таблице приведена сводка характеристик времени существования и видимости для


большинства идентификаторов. В первых трех столбцах приведены атрибуты, определяющие время
существования и видимость. Идентификатор с атрибутами, указанными в первых трех столбцах, имеет
время существования и видимость, указанные в четвертом и пятом столбцах. Однако таблица охватывает не
все возможные случаи. Дополнительные сведения см. в статье о классах хранения.

Сводка времени существования и видимости


РЕЗУЛЬТАТ: ;
АТРИБУТЫ: СПЕЦИФИКАТОР
ВРЕМЯ
УРОВЕНЬ ЭЛЕМЕНТ КЛАССА ХРАНЕНИЯ СУЩЕСТВОВАНИЯ ВИДИМОСТЬ

Область видимости Определение static Global Оставшаяся часть


файла переменной файла исходного
кода, в котором
встречается

Объявление extern Global Оставшаяся часть


переменной файла исходного
кода, в котором
встречается

Прототип или static Global Один файл


определение исходного кода
функции

Прототип функции extern Global Оставшаяся часть


файла исходного
кода

Область действия Объявление extern Global Блок


блока переменной

Определение static Global Блок


переменной

Определение auto или Локальная Block


переменной register

Пример
Описание
В следующем примере показаны блоки, вложение и видимость переменных:

Код
// Lifetime_and_Visibility.c

#include <stdio.h>

int i = 1; // i defined at external level

int main() // main function defined at external level


{
printf_s( "%d\n", i ); // Prints 1 (value of external level i)
{ // Begin first nested block
int i = 2, j = 3; // i and j defined at internal level
printf_s( "%d %d\n", i, j ); // Prints 2, 3
{ // Begin second nested block
int i = 0; // i is redefined
printf_s( "%d %d\n", i, j ); // Prints 0, 3
} // End of second nested block
printf_s( "%d\n", i ); // Prints 2 (outer definition
// restored)
} // End of first nested block
printf_s( "%d\n", i ); // Prints 1 (external level
// definition restored)
return 0;
}

Комментарии
В этом примере имеется 4 уровня видимости: внешний уровень и 3 уровня блоков. Значения выводятся на
экран, как указано в комментариях после каждого оператора.

См. также
Время жизни, область, видимость и компоновка
Компоновка
13.10.2020 • 2 minutes to read • Edit Online

Имена идентификаторов могут относиться к разным идентификаторам в разных областях. Идентификатор,


объявленный в разных областях или в одной и той же области несколько раз, можно настроить таким
образом, чтобы он ссылался на один идентификатор или функцию, с помощью процесса компоновки.
Компоновка определяет части программы, в которых можно сослаться на идентификатор (его видимость).
Существует три типа компоновки: внутренняя, внешняя и без компоновки.

См. также
Использование ключевого слова extern для задания компоновки
Внутренняя компоновка
13.10.2020 • 2 minutes to read • Edit Online

Если объявление идентификатора области доступности файла для объекта или функции содержит
описатель класса хранения типа static , идентификатор имеет внутреннюю компоновку. В противном
случае идентификатор имеет внешнюю компоновку. Использование нетерминального параметра storage-
class-specifier приводится в статье Классы хранения.
В пределах одной записи преобразования каждый экземпляр идентификатора с внутренней компоновкой
обозначает тот же идентификатор или функцию. Идентификаторы с внутренней компоновкой уникальны
для конкретной записи преобразования.

См. также
Использование ключевого слова extern для задания компоновки
Внешняя компоновка
13.10.2020 • 2 minutes to read • Edit Online

Если в первом объявлении на уровне области видимости файла для идентификатора не используется
описатель класса хранения static , объект имеет внешнюю компоновку.

Если в объявлении идентификатора для функции отсутствует описатель storage-class-specifier, его


компоновка определяется так же, как если бы он был объявлен с описателем storage-class-specifier extern .
Если объявление идентификатора объекта содержит область видимости файла и не содержит описатель
storage-class-specifier, его компоновка является внешней.
Имя идентификатора с внешней компоновкой обозначает ту же функцию или объект данных, что и любое
другое объявление того же имени с внешней компоновкой. Два объявления могут находиться в одной
записи преобразования или в разных записях преобразования. Если объект или функция также имеет
глобальное время жизни, объект или функция используется совместно всей программой.

См. также
Использование ключевого слова extern для задания компоновки
Без компоновки
13.10.2020 • 2 minutes to read • Edit Online

Если объявление идентификатора в блоке не содержит описатель класса хранения extern , этот
идентификатор не имеет компоновки и уникален для функции.

Следующие идентификаторы не имеют компоновки:

идентификатор, объявленный в качестве нечто отличного от объекта или функции;

идентификатор, объявленный в качестве параметра функции;

идентификатор области доступности блока для объекта, объявленного без описателя класса
хранения extern .

Если идентификатор не имеет компоновки, повторное объявление того же имени (в деклараторе или
спецификаторе типа) на том же уровне области видимости приводит к появлению ошибки
переопределения символов.

См. также
Использование ключевого слова extern для задания компоновки
Пространства имен
13.10.2020 • 4 minutes to read • Edit Online

Компилятор настраивает пространства имен, чтобы различать идентификаторы, используемые для


различных типов элементов. Имена в каждом пространстве имен должны быть уникальными во избежание
конфликтов, но одинаковые имена могут использоваться в нескольких пространствах имен. Это означает ,
что можно использовать один и тот же идентификатор для двух или более различных элементов при
условии, что элементы расположены в разных пространствах имен. Компилятор может разрешить ссылки
на основе синтаксического контекста идентификатора в программе.

NOTE
Не следует путать ограниченную нотацию C пространства имен с возможностью пространства имен C++.
Дополнительные сведения см. в разделе Пространства имен (C++) в справочнике по языку C++.

Ниже приводится список пространств имен, используемых в C.

Метки операторов. Именованные метки операторов являются частью операторов. За определениями меток
операторов всегда следует двоеточие, но определения не являются частью меток case . Метки операторов
всегда используются сразу за ключевым словом goto . Метки операторов не должны отличаться от других
имен или имен меток в других функциях.

Теги структур, объединений и перечислений. Эти теги являются частью указателей на тип структуры,
объединения и перечисления и при их наличии всегда следуют сразу за зарезервированными словами
struct , union или enum . Имена тегов должны отличаться от всех других тегов структур, перечислений
или объединений с такой же видимостью.

Элементы структур или объединений. Имена элементов выделены в пространствах имен, связанных с
каждыми типом структуры и объединения. То есть один и тот же идентификатор может быть именем
компонента в любом количестве структур или объединений одновременно. Определения имен
компонентов всегда находятся в описателях типа структуры или объединения. Имена компонентов всегда
следуют сразу за операторами выбора члена ( -> и . ). Имя члена должно быть уникальным в пределах
структуры или объединения, но оно не обязательно должно отличаться от других имен в программе,
включая имена членов различных структур и объединений или имя самой структуры.

Обычные идентификаторы. Все другие имена находятся в пространстве имен, которое содержит
переменные, функции (включая формальные параметры и локальные переменные) и константы
перечисления. Имена идентификаторов имеют вложенную видимость, поэтому их можно переопределять в
блоках.

Имена typedef. Эти имена нельзя использовать в качестве идентификаторов в одной и той же области.

Например, поскольку теги структуры, члены структуры и имена переменных находятся в трех разных
пространствах имен, три элемента с именем student в этом примере не конфликтуют. Контекст каждого
элемента позволяет правильно интерпретировать каждое вхождение student в программе.
(Дополнительные сведения о структурах см. в разделе Объявления структур.)
struct student {
char student[20];
int class;
int id;
} student;

Если student отображается после ключевого слова struct , компилятор распознает его как тег структуры.
Если student отображается после оператора выбора члена ( -> или . ), имя ссылается на член структуры. В
других контекстах student ссылается на переменную структуры. Однако не рекомендуется перегружать
пространство имен тега, поскольку это искажает смысл.

См. также
Структура программы
Объявления и типы
06.05.2020 • 2 minutes to read • Edit Online

В этом разделе описывается объявление и инициализация переменных, функций и типов. Язык C


содержит стандартный набор базовых типов данных. Имеется также возможность добавлять
собственные типы данных, называемые производными типами, путем объявления новых типов на основе
уже определенных. Рассматриваются следующие темы:

Общие сведения об объявлениях

Классы хранения в C

Описатели типов С

Квалификаторы типов

Деклараторы и объявления переменных

Интерпретация сложных деклараторов

Инициализация

Хранение базовых типов

Неполные типы

Объявления Typedef

Расширенные атрибуты классов хранения в C

См. также
Справочник по языку C
Общие сведения об объявлениях
13.10.2020 • 7 minutes to read • Edit Online

Объявление задает интерпретацию и атрибуты набора идентификаторов. Объявление, которое также


резервирует область хранения для объекта или функции, именованной идентификатором, называется
определением. В языке C объявления переменных, функций и типов имеют следующий синтаксис:

Синтаксис
declaration :
declaration-specifiers attribute-seq необ. init-declarator-list необ. ;

/* attribute-seq необ. относится только к системам Microsoft */

declaration-specifiers :
storage-class-specifier declaration-specifiers необ.
type-specifier declaration-specifiers необ.
type-qualifier declaration-specifiers необ.

init-declarator-list :
init-declarator
init-declarator-list , init-declarator

init-declarator :
declarator
declarator = initializer

NOTE
Этот синтаксис для declaration не будет повторяться в следующих разделах. Синтаксис в следующих
разделах обычно начинается с нетерминального оператора объявления declarator .

Объявления в init-declarator-list содержат именуемые идентификаторы, а сокращение init означает


инициализатор. init-declarator-list — это последовательность операторов объявления, разделенных
запятыми. Каждый из них может содержать дополнительную информацию о типе и (или) инициализатор.
В declarator содержатся объявляемые идентификаторы (при наличии). Нетерминальные описатели
declaration-specifiers состоят из последовательности спецификаторов типа и класса хранения, которые
указывают компоновку, время хранения и по меньшей мере часть типа сущностей, обозначаемых
операторами объявления. Объявления состоят из произвольного сочетания описателей класса хранения,
описателей типов, квалификаторов типов, операторов объявлений и инициализаторов.

Объявления могут содержать один или несколько из необязательных атрибутов, перечисленных в


параметре attribute-seq , а сокращение seq означает последовательность. Эти атрибуты, используемые
только в системах Майкрософт , выполняют несколько функций, которые рассматриваются в этой книге.

В общей форме объявления переменных в параметре type-specifier задается тип данных для переменной.
type-specifier может быть составным, например иметь модификаторы const и volatile . В параметре
declarator содержится имя переменной, которое может быть изменено для объявления массива или типа
указателя. Например, примененная к объекту директива
int const *fp;

В приведенном выше примере переменная с именем fp объявляется как указатель на неизменяемое (


const ) значение int . В объявлении можно определить несколько переменных; для этого используется
несколько деклараторов, которые разделяются запятыми.

Объявление должно содержать по меньшей мере один декларатор, или его спецификатор типа должен
объявлять тег структуры, тег объединения или члены перечисления. Деклараторы предоставляют всю
остальную информацию об идентификаторе. Оператор объявления — это идентификатор, который
можно изменить с помощью квадратных скобок ( [ ] ), звездочек ( * ) или круглых скобок ( ( ) ) для
объявления типов массива, указателя или функции, соответственно. При объявлении простых переменных
(например символьных, целочисленных или с плавающей запятой) или структур и объединений простых
переменных декларатор ( declarator ) представляет собой только идентификатор. Дополнительные
сведения о деклараторах см. в статье Деклараторы и объявления переменных.

Все определения неявным образом являются объявлениями, но не все объявления являются


определениями. Например, объявления переменных, которые начинаются со описателя класса хранения
extern , являются ссылающимися, но не определяющими объявлениями. Если сослаться на внешнюю
переменную необходимо до ее определения или если она определена в другом исходном файле, а не в том,
в котором она используется, то объявление extern является обязательным. Когда программа ссылается на
объявления, область хранения не выделяется. Кроме того, инициализировать переменные в объявлениях
нельзя.

В объявлениях переменных должен быть указан класс хранения или тип (или и то, и другое). За
исключением ключевого слова __declspec , в объявлениях допускается только один описатель класса
хранения. Некоторые описатели класса хранения не допускаются в некоторых контекстах. Класс хранения
__declspec может использоваться с другими описателями класса хранения; его можно указывать более
одного раза. Спецификатор класса хранения для объявления влияет только на то, каким образом
объявленный элемент хранится и инициализируется, и какие части программы могут ссылаться на
элемент.

В C определены терминальные описатели storage-class-specifier следующих типов: auto , extern ,


register , static и typedef . Кроме того , Microsoft C включает терминальный описатель
storage-class-specifier __declspec . Все терминальные описатели storage-class-specifier , за
исключением typedef и __declspec , рассматриваются в статье Классы хранения в C. Сведения о typedef
см. в статье Декларации typedef . Сведения о __declspec см. в статье Расширенные атрибуты классов
хранения в C.

Местоположение объявления в исходном коде программы, а также наличие и отсутствие других


объявлений переменной — это факторы, которые имеют значения для определения срока жизни
переменных. Возможно несколько повторных объявлений, однако определение может создаваться только
один раз. Однако определение может использоваться в нескольких блоках трансляции. Для объектов с
внутренней компоновкой это правило применяется отдельно для каждого блока трансляции, поскольку
объекты с внутренней компоновкой уникальны для блока трансляции. Для объектов с внешней
компоновкой это правило применяется ко всей программе. Дополнительные сведения о видимости см. в
статье Время жизни, область, видимость и компоновка.

Спецификаторы типа предоставляют некоторые сведения о типах данных в идентификаторах. По


умолчанию используется описатель типа int . Дополнительные сведения см. в разделе Спецификаторы
типа. Спецификаторы типа также могут определять теги типа, имена компонентов структуры и
объединения, а также перечисления константы перечисления. Дополнительные сведения см. в статьях
Объявления перечислений C, Объявления структур и Объявления объединений.
Есть два типа терминальных описателей type-qualifier : const и volatile . Эти квалификаторы
определяют дополнительные свойства типов, которые действуют только при обращении к объектам
соответствующих типов с l-значений. Дополнительные сведения о ключевых словах const и volatile см.
в разделе Квалификаторы типов. Определение l-значений см. в разделе Выражения L-Value и R-Value.

См. также
Краткие сведения о синтаксисе языка C
Объявления и типы
Общие сведения об объявлениях
Классы хранения в C
13.10.2020 • 2 minutes to read • Edit Online

"Класс хранения" переменной определяет время существования элемента: глобальное или локальное. В
языке С это время существования называется "статическое" или "автоматическое". Элемент с
глобальным временем существования присутствует и имеет значение на протяжении всего исполнения
программы. Все функции имеют глобальное время существования.

Автоматические переменные или переменные с локальным временем существования получают новое


место хранения всякий раз, когда контроль исполнения переходит к блоку, в котором они определены.
Когда выполнение возвращается, переменные более не имеют понятных значений.

C предоставляет следующие описатели класса хранения:

Синтаксис
storage-class-specifier:
auto
register
static
extern
typedef
__declspec ( extended-decl-modifier-seq ) /* Относится только к системам Майкрософт */
За исключением __declspec , в составе declaration-specifier в объявлении можно использовать только
один описатель storage-class-specifier. Если нет спецификации класса хранения, объявления в блоке
создают автоматические объекты.

Элементы, объявленные с описателем auto или register , имеют локальное время существования.
Элементы, объявленные с описателем static или extern , имеют глобальное время существования.

Поскольку typedef и __declspec семантически отличаются от других четырех терминалов storage-class-


specifier, они рассматриваются отдельно. Подробные сведения о typedef см. в статье Объявления
typedef . Подробные сведения о __declspec см. в статье Расширенные атрибуты классов хранения.

Размещение объявлений переменных и функций в файлах исходного кода также влияет на класс
хранения и видимость. Объявления вне определений функций отображаются на внешнем уровне.
Объявления в составе определений функций отображаются на внутреннем уровне.

Точное значение каждого определителя класса хранения зависит от двух факторов:

уровня отображения объявления (внешний или внутренний)

типа объявляемого элемента (переменная или функция)

В статьях Описатели классов хранения для объявлений внешнего уровня и Описатели классов хранения
для объявлений внутреннего уровня описаны терминалы storage-class-specifier для каждого типа
объявлений и поведение по умолчанию в случае отсутствия storage-class-specifier в декларации
переменной. Статья Описатели классов хранения с объявлениями функций поможет разобраться с
описателями storage-class, используемыми с функциями.

См. также
Объявления и типы
Спецификаторы классов хранения для объявлений
внешнего уровня
13.10.2020 • 7 minutes to read • Edit Online

Внешние переменные — это переменные в области видимости файла. Они определяются вне конкретной
функции и потенциально доступны для множества функций. Функции можно определить только на
внешнем уровне, и, следовательно, они не могут быть вложенными. По умолчанию все ссылки на внешние
переменные и функции с одинаковым именем являются ссылками на один и тот же объект , что означает ,
что они имеют внешнее связывание. (Чтобы переопределить такое поведение, можно использовать
ключевое слово static .)

Объявления переменных на внешнем уровне являются определениями переменных (определяющие


объявления) или ссылками на переменные, определенные в другом месте (ссылающиеся объявления).
Внешнее объявление переменной, которое также инициализирует переменную (неявно или явно), является
определяющим объявлением переменной. Определение на внешнем уровне может принимать различные
формы.

Переменная, объявляемая с использованием описателя класса хранения static . Вы можете явно


инициализировать переменную static с использованием константного выражения, как описано в
статье Инициализация. Если опустить инициализатор, переменная инициализируется значением 0 по
умолчанию. Например, следующие два оператора считаются определениями переменной k .

static int k = 16;


static int k;

Переменная, которая явно инициализируется на внешнем уровне. Например, int j = 3; — это


определение переменной j .

В объявлениях переменных на внешнем уровне (т. е. вне любых функций) можно либо использовать
описатель класса хранения static или extern , либо полностью опустить его. Вы не можете использовать
терминальные описатели storage-class-specifier auto и register на внешнем уровне.

После определения переменной на внешнем уровне она становится видимой во всей оставшейся части
записи преобразования. Переменная невидима до ее объявления в том же исходном файле. Кроме того, она
будет невидима в других исходных файлах программы, пока объявление не сделает ее видимой, как
описано ниже.

Ниже приводятся правила в отношении static .


Переменные, объявленные вне всех блоков без ключевого слова static , всегда сохраняют свои
значения в течение всего хода выполнения программы. Чтобы ограничить доступ переменных к
определенной записи преобразования, необходимо использовать ключевое слово static . Это
позволяет применить к ним внутреннее связывание. Чтобы сделать их глобальными для всей
программы, опустите явный класс хранения или укажите ключевое слово extern (см. правила в
следующем списке). Это позволяет применить к ним внешнее связывание. Внутренняя и внешняя
компоновки также описаны в разделе Компоновка.

Указать переменную на внешнем уровне можно только один раз в рамках программы. Можно указать
другую переменную с тем же именем и описатель класса хранения static в другой записи
преобразования. Так как каждое определение static является видимым только в пределах
собственной записи преобразования, конфликт не произойдет. Это удобный способ скрыть имена
идентификаторов, которые должны совместно использоваться функциями в одной единице
трансляции, но должны быть невидимы для других таких единиц.

Описатель класса хранения static также может применяться к функциям. Если функция объявлена
как static , ее имя невидимо вне файла, в котором она объявлена.

Ниже приведены правила использования extern .


Описатель класса хранения extern объявляет ссылку на переменную, определенную в другом месте.
С помощью объявления extern можно сделать определение в другом исходном файле видимым или
сделать переменную видимой до ее определения в том же исходном файле. После объявления
ссылки на переменную на внешнем уровне переменная становится видимой во всей остальной части
единицы трансляции, в которой находится объявленная ссылка.

Чтобы ссылка extern стала допустимой, необходимо объявить переменную, на которую она
ссылается, один и только один раз на внешнем уровне. Это определение (без класса хранения extern
) может находиться в любой из единиц трансляции, составляющих программу.

Пример
В примере ниже показаны внешние объявления.

/******************************************************************
SOURCE FILE ONE
*******************************************************************/
#include <stdio.h>

extern int i; // Reference to i, defined below


void next( void ); // Function prototype

int main()
{
i++;
printf_s( "%d\n", i ); // i equals 4
next();
}

int i = 3; // Definition of i

void next( void )


{
i++;
printf_s( "%d\n", i ); // i equals 5
other();
}

/******************************************************************
SOURCE FILE TWO
*******************************************************************/
#include <stdio.h>

extern int i; // Reference to i in


// first source file
void other( void )
{
i++;
printf_s( "%d\n", i ); // i equals 6
}
Два исходных файла в этом примере содержат три внешних объявления i . Только одно объявление
является определяющим. Данное объявление

int i = 3;

определяет глобальную переменную i и инициализирует ее начальным значением 3. Ссылочное


объявление i вверху первого исходного файла, которое использует extern , делает глобальную
переменную видимой до объявления, которое ее определяет. Ссылающееся объявление i во втором
исходном файле также делает переменную видимой в этом исходном файле. Если определяющий
экземпляр переменной не указан в записи преобразования, компилятор предполагает , что имеется
ссылающееся объявление

extern int x;

и что определяющая ссылка

int x = 0;

отображается в другой записи преобразования программы.

Все три функции ( main , next и other ) выполняют одну и ту же задачу: они расширяют переменную i и
отображают ее значение. Отображаются значения 4, 5 и 6.

Если бы переменная i не была инициализирована, ей автоматически было бы присвоено значение 0. В


этом случае были бы отображены значения 1, 2 и 3. Дополнительные сведения об инициализации
переменных см. в разделе Инициализация.

См. также
Классы хранения в C
Спецификаторы классов хранения для объявлений
внутреннего уровня
13.10.2020 • 2 minutes to read • Edit Online

Любой из четырех терминальных описателей storage-class-specifier можно использовать для объявления


переменных на внутреннем уровне. Если в таком объявлении не указан storage-class-specifier , по
умолчанию используется класс хранения auto . Поэтому ключевое слово auto редко встречается в
программах на языке C.

См. также
Классы хранения в C
Описатель класса хранения auto
13.10.2020 • 2 minutes to read • Edit Online

Описатель класса хранения auto объявляет автоматическую переменную, то есть переменную с локальным
временем существования. Переменная auto доступна только в том блоке, в котором она объявлена.
Объявления переменных auto могут содержать инициализаторы, как описано в статье Инициализация.
Поскольку переменные с классом хранения auto не инициализируются автоматически, необходимо явно
инициализировать их при объявлении или присвоить им начальные значения в блоке. Для
неинициализированных переменных auto значения не определены. (Локальная переменная с классом
хранения auto или register инициализируется заново каждый раз, когда она попадает в область
доступности, если для нее указан инициализатор.)

Внутреннюю переменную static (статическую переменную с локальной областью доступности или


областью доступности в блоке) можно инициализировать адресом любого внешнего элемента или элемента
static , но не адресом элемента auto , поскольку адрес элемента auto не является константой.

См. также
Ключевое слово auto
Спецификатор класса хранения register
13.10.2020 • 2 minutes to read • Edit Online

Блок , относящийся только к системам Майкрософт

Компилятор Microsoft C/C++ не учитывает пользовательские запросы на переменные регистра. Но в целях


обеспечения переносимости компилятор учитывает всю остальную семантику, связанную с ключевым
словом register . Например, невозможно применить унарный оператор взятия адреса ( & ) к объекту
регистра. Кроме того, ключевое слово register невозможно использовать в массивах.

Завершение блока , относящегося только к системам Майкрософт

См. также
Спецификаторы классов хранения для объявлений внутреннего уровня
Спецификатор класса хранения static
13.10.2020 • 2 minutes to read • Edit Online

Переменная, объявленная на внутреннем уровне с помощью описателя класса хранения static , имеет
глобальное время существования, но доступна только внутри блока, в котором она объявлена. Описатель
static полезно использовать в константных строках, потому что при этом снимается нагрузка частой
инициализации в часто вызываемых функциях.

Примечания
Если переменная с типом static не инициализирована явно, она инициализируется со значением 0 по
умолчанию. Внутри функции static выделяет хранилище и служит определением. Внутренние статические
переменные представляют закрытое постоянное хранилище, видимое только одной функции.

См. также
Классы хранения в C
Storage classes (C++) (Классы хранения (C++))
Спецификатор класса хранения extern
13.10.2020 • 2 minutes to read • Edit Online

Переменная, объявленная с использованием описателя для класса хранения extern , представляет собой
ссылку на переменную с тем же именем, определенную в другом исходном файле. Она используется, чтобы
сделать видимым определение переменной внешнего уровня. Для переменной, объявленной как extern , не
выделено хранилище; по сути, это только имя.

Пример
Этот пример иллюстрирует объявления на внутреннем и внешнем уровнях.

// Source1.c

int i = 1;

// Source2. c

#include <stdio.h>

// Refers to the i that is defined in Source1.c:


extern int i;

void func(void);

int main()
{
// Prints 1:
printf_s("%d\n", i);
func();
return;
}

void func(void)
{
// Address of global i assigned to pointer variable:
static int *external_i = &i;

// This definition of i hides the global i in Source.c:


int i = 16;

// Prints 16, 1:
printf_s("%d\n%d\n", i, *external_i);
}

В этом примере переменная i определяется в Source1.c с исходным значением 1. Объявление extern в


Source2.c делает переменную i доступной в этом файле.
В функции func адрес глобальной переменной i используется для инициализации переменной указателя
external_i с описателем static . Это возможно , поскольку глобальная переменная имеет время
существования типа static , то есть ее адрес не меняется во время исполнения программы. Кроме того,
переменная i определяется в пределах области func как локальная переменная с исходным значением 16.
Это определение не влияет на значение переменной i внешнего уровня, которое скрыто благодаря
использованию соответствующего имени для локальной переменной. Значение глобальной переменной i
теперь доступно только через указатель external_i .
См. также
Спецификаторы классов хранения для объявлений внутреннего уровня
Спецификаторы классов хранения с объявлениями
функций
13.10.2020 • 2 minutes to read • Edit Online

В объявлениях функций можно использовать описатель класса хранения static или extern . Функции
всегда имеют глобальное время существования.

Блок , относящийся только к системам Microsoft

Объявления функций на внутреннем уровне имеют то же значение, что и объявления функций на внешнем
уровне. Это означает , что функция видна с момента объявления на протяжении всего времени
существования записи преобразования, даже если она объявлена с локальной областью видимости.

Завершение блока , относящегося только к системам Майкрософт

Правила видимости для функций слегка отличаются от правил для переменных следующим.

Функция, объявленная как static , видна только в пределах исходного файла, в котором она
определена. Функции в том же исходном файле могут вызывать функцию static , но функции в
других исходных файлах не могут получить прямой доступ к ней по имени. Можно объявить другую
функцию static с тем же именем в другом исходном файле, не создавая конфликта.

Функции, объявленные как extern , видны во всех исходных файлах программы (если впоследствии
такая функция не будет повторно объявлена как static ). Любая функция может вызывать функцию
extern .
Объявления функций, опускающие описатель класса хранения, по умолчанию являются extern .
Блок , относящийся только к системам Microsoft

В системах Майкрософт можно повторно определять идентификатор extern как static .


Завершение блока , относящегося только к системам Майкрософт

См. также
Классы хранения в C
Спецификаторы типов C
13.10.2020 • 4 minutes to read • Edit Online

Спецификаторы типа в объявлениях определяют тип объявления переменной или функции.

Синтаксис
type-specifier: void char short int long float double signed unsigned
struct-or-union-specifier enum-specifier typedef-name
Типы signed char , signed int , и signed long int вместе с аналогичными типами
signed short int
unsigned и enum совокупно именуются целочисленными типами. Описатели типов float , double и
long double называются типами с плавающей точкой или плавающей запятой. Любой спецификатор
целочисленного типа или типа с плавающей запятой можно использовать в объявлении переменной или
функции. Если в объявлении отсутствует описатель type-specifier, для него предполагается тип int .

Необязательные ключевые слова signed и unsigned могут указываться перед любым целочисленным
типом или после него, за исключением enum . Также их можно использовать отдельно в качестве
описателей типа, и тогда они трактуются соответственно как signed int и unsigned int . Если ключевое
слово int используется отдельно, оно обрабатывается как signed . Если ключевые слова long и short
используются отдельно, они трактуются как long int и short int .

Типы перечисления считаются базовыми типами. Описатели типов для типов перечисления
рассматриваются в статье Объявления перечислений C.

Ключевое слово void используется для трех целей: задание типа возвращаемого значения функции,
задание списка типов аргументов для функции, не принимающей аргументов, и задание указателя на
неуказанный тип. Тип void можно использовать для объявления функций, не возвращающих никаких
значений, или для объявления указателя на неуказанный тип. В статье Аргументы описано, как
обрабатывается void , если это единственное ключевое слово в скобках после имени функции.

Блок , относящийся только к системам Microsoft

Проверка типов теперь соответствует требованиям ANSI, то есть типы short и int считаются разными
типами. Например, это является переопределением в компиляторе Microsoft C, которое принималось
предыдущими версиями компилятора.

int myfunc();
short myfunc();

Следующий пример также создает предупреждение о косвенном обращении к разным типам:

int *pi;
short *ps;

ps = pi; /* Now generates warning */

Компилятор Microsoft C также выдает предупреждения в случае разного использования знака (типы со
знаком и без знака). Пример:
signed int *pi;
unsigned int *pu

pi = pu; /* Now generates warning */

Выражения типа void вычисляются для учета побочных эффектов. Невозможно каким-либо образом
использовать (несуществующее) значение выражения типа void ; также невозможно преобразовать
выражение типа void (с помощью явного или неявного преобразования) в любой тип, кроме void . При
использовании в контексте, в котором требуется выражение void , выражения любого другого типа его
значение игнорируется.

Для обеспечения соответствия спецификации ANSI тип void** не может использоваться как int** . В
качестве указателя на неуказанный тип можно использовать только void * .

Завершение блока , относящегося только к системам Майкрософт

С помощью объявлений typedef можно создавать дополнительные описатели типа, как описано в статье
Объявления Typedef. Сведения о размерах для каждого типа см. в статье Хранение базовых типов.

См. также
Объявления и типы
Спецификаторы и эквиваленты типов данных
13.10.2020 • 2 minutes to read • Edit Online

В этой книге в большинстве случаев вместо полных форм описателей типов используются формы,
приведенные в следующей таблице. При этом предполагается, что тип char является знаковым по
умолчанию. Таким образом, если в этой книге указывается тип char , то это означает то же, что и
signed char .

Спецификаторы типов и их эквиваленты


СПЕЦИФИКАТОРЫ ТИПОВ ЭКВИВАЛЕНТЫ

signed char 1 char

signed int signed , int

signed short int short , signed short

signed long int long , signed long

unsigned char —

unsigned int unsigned

unsigned short int unsigned short

unsigned long int unsigned long

float —

long double 2 —

1 Если вы указали, что


тип char по умолчанию является беззнаковым (указав параметр компилятора /J ),
вы не сможете сократить signed char до char .
2 В 32- и 64-разрядных операционных системах компилятор Microsoft С устанавливает соответствие между
типами long double и double .
Блок , относящийся только к системам Microsoft

При помощи параметра компилятора /J можно указать, что тип char по умолчанию является не
signed char , а unsigned char . При использовании этого параметра описатель char означает то же, что и
unsigned char . Для объявления знакового символьного значения необходимо использовать ключевое слово
signed . Если значение char явным образом объявлено как signed , то параметр /J на него не влияет , и
его расширение до типа int выполняется с расширением знака. Расширение типа char до типа int
выполняется с дополнением нулями.

Завершение блока , относящегося только к системам Майкрософт


См. также
Спецификаторы типов C
Квалификаторы типов
13.10.2020 • 4 minutes to read • Edit Online

Квалификаторы типов предоставляют идентификатору одно из двух свойств. Квалификатор типа const
объявляет объект как неизменяемый. Квалификатор типа volatile объявляет элемент , значение которого
можно изменить допустимым образом с помощью средств, недоступных программе, в которой он
находится, таких как выполняемый в данный момент поток.

Квалификаторы типов const и volatile могут использоваться в объявлении только один раз.
Квалификаторы типов могут использоваться с любым описателем типа; однако они не могут находиться
после первой запятой в объявлении нескольких элементов. Например, следующие объявления допустимы.

typedef volatile int VI;


const int ci;

Следующие объявления не допустимы.

typedef int *i, volatile *vi;


float f, const cf;

Квалификаторы типов имеют смысл только при обращении к идентификаторам как к l-значениям в
выражениях. Дополнительные сведения о левосторонних значениях и выражениях см. в статье Выражения
L-Value и R-Value.

Синтаксис
type-qualifier: constvolatile
Ниже представлены допустимые объявления const и volatile .

int const *p_ci; /* Pointer to constant int */


int const (*p_ci); /* Pointer to constant int */
int *const cp_i; /* Constant pointer to int */
int (*const cp_i); /* Constant pointer to int */
int volatile vint; /* Volatile integer */

Если спецификация типа массива включает квалификаторы типов, определяется элемент , а не тип массива.
Если спецификация типа функции включает квалификаторы, поведение не определено. Ни volatile , ни
const не влияют на диапазон значений или арифметические свойства объекта.

В следующем списке описано использование const и volatile .


Ключевое слово const можно использовать для изменения любого фундаментального или
агрегатного типа, указателя на объект любого типа или typedef . Если элемент объявлен только с
квалификатором типа const , считается, что он имеет тип const int . Переменную с квалификатором
const можно инициализировать в области хранения, доступной только для чтения, или переместить
в такую область. Ключевое слово const полезно при объявлении указателей на значения const .
Так вы сообщите функции, что этот указатель нельзя изменять.

Компилятор предполагает , что в любом месте программы к переменной volatile может обратиться
неизвестный процесс, который использует или изменяет ее значение. Следовательно, независимо от
оптимизаций, указанных в командной строке, необходимо создать код для каждого назначения
переменной volatile или ссылки на нее, даже если кажется, что он ничего не делает.

Если volatile используется отдельно, предполагается int . Описатель типа volatile можно
использовать для предоставления надежного доступа к специальным адресам памяти. Используйте
volatile с объектами данных, к которым можно получить доступ или которые можно изменить с
помощью обработчиков сигналов, одновременного выполнения программ или специального
оборудования, например регистров управления MMIO. Можно объявить переменную как volatile на
весь срок ее существования или объявить как volatile только одну ссылку.

Элемент может одновременно быть const и volatile , и тогда его невозможно изменить
допустимым образом в той же программе, но можно изменить в некотором асинхронном процессе.

См. также
Объявления и типы
Деклараторы и объявления переменных
13.10.2020 • 4 minutes to read • Edit Online

В остальной части данного раздела описывается форма и значение объявлений для переменных типов,
включенных в этот список. В частности, в остальных разделах объясняется, как объявить следующие
объекты.

ТИП ПЕРЕМЕННОЙ ОПИСАНИЕ

Простые переменные Однозначные переменные целочисленного типа или


типа с плавающей запятой

Массивы Переменные, состоящие из коллекции элементов того же


типа

Указатели Переменные, указывающие на другие переменные и


содержащие расположения переменных (в виде адресов)
вместо значений

Переменные перечисления Простые переменные с целочисленным типом,


содержащие одно значение из набора именованных
целочисленных констант

Структуры Переменные, состоящие из коллекции значений, которые


могут иметь разные типы

Объединения Переменные, состоящие из нескольких значений разных


типов, занимающих одинаковое пространство для
хранения

Декларатор — это часть объявления, задающая имя, которое нужно вставить в программу. Он может
включать модификаторы, например * (указатель на), и любые ключевые слова соглашения о вызовах
Майкрософт.

Блок , относящийся только к системам Microsoft

В деклараторе

__declspec(thread) char *var;

char — это описатель типа, __declspec(thread) и * — это модификаторы, а var — это имя
идентификатора.

Завершение блока , относящегося только к системам Майкрософт

Деклараторы используются для объявления массивов значений, указателей на значения и функций,


возвращающих значения заданного типа. Деклараторы отображаются в объявлениях массивов и
указателей, описанных далее в этом разделе.

Синтаксис
declarator:
pointeropt direct-declarator
direct-declarator:
identifier
( declarator )
direct-declarator [ constant-expressionopt ]
direct-declarator ( parameter-type-list )
direct-declarator ( identifier-listopt )
pointer:
* type-qualifier-listopt
* type-qualifier-listopt pointer
type-qualifier-list:
type-qualifier
type-qualifier-list type-qualifier

NOTE
См. соответствующий синтаксис для объявления в разделе Обзор объявлений или Краткие сведения о синтаксисе
языка C для получения сведений о синтаксисе, который ссылается на декларатор.

Если декларатор состоит из неизмененного идентификатора, объявляемый элемент имеет базовый тип.
Если звездочка (* ) отображается слева от идентификатора, тип изменяется на тип указателя. Если после
идентификатора следуют квадратные скобки ( [ ] ), тип изменяется на тип массива. Если после
идентификатора следуют скобки, тип меняется на тип функции. Дополнительные сведения об
интерпретации приоритетности в пределах объявлений см. в разделе Интерпретация более сложных
деклараторов.

Каждый декларатор объявляет по крайней мере один идентификатор. Декларатор должен включать
описатель типа, чтобы называться полным объявлением. Описатель типа предоставляет тип элементов
типа массива, тип объекта, к которому относится тип указателя, или тип возвращаемого значения
функции.

Объявления массивов и указателей более подробно обсуждаются далее в этом разделе. В следующем
примере проиллюстрировано несколько простых форм деклараторов.

int list[20]; // Declares an array of 20 int values named list


char *cp; // Declares a pointer to a char value
double func( void ); // Declares a function named func, with no
// arguments, that returns a double value
int *aptr[10] // Declares an array of 10 pointers

Блок , относящийся только к системам Microsoft

Компилятор Microsoft C не ограничивает число деклараторов, которые могут изменять арифметические,


структурные типы или типы объединений. Это число ограничивается только объемом доступной памяти.

Завершение блока , относящегося только к системам Майкрософт

См. также
Объявления и типы
Простые объявления переменных
13.10.2020 • 2 minutes to read • Edit Online

Объявление обычной переменной, простейшей формы прямого декларатора, указывает имя и тип
переменной. Оно также указывает класс хранения и тип данных переменной.

Классы хранения или типы (или и то, и другое) требуются в объявлениях переменных. Нетипизированные
переменные (например, var; ) создают предупреждения.

Синтаксис
declarator:
pointeropt direct-declarator
direct-declarator:
identifier
identifier:
nondigit
identifier nondigit
identifier digit
В случае арифметического типа, типа структуры, типа объединения, типа перечисления, типа void и типов,
представляемых именами typedef , простые деклараторы можно использовать в объявлении, поскольку
описатель предоставляет всю вводимую информацию. Для типов указателя, массива и функций требуются
более сложные деклараторы.

Чтобы указать несколько переменных в одном объявлении, можно использовать список идентификаторов,
разделенных запятыми ( , ). Все переменные, определенные в объявлении, имеют один и тот же базовый тип.
Пример:

int x, y; /* Declares two simple variables of type int */


int const z = 1; /* Declares a constant value of type int */

Переменные x и y могут содержать любое значение в наборе, определенном типом int для конкретной
реализации. Простой объект z инициализируется значением 1 и не может быть изменен.

Если бы объявление z было выполнено для неинициализированной статической переменной или в


области видимости файла, было бы получено начальное значение 0, которое было бы неизменяемым.

unsigned long reply, flag; /* Declares two variables


named reply and flag */

В этом примере обе переменные reply и flag имеют тип unsigned long и содержат целочисленные
значения без знака.

См. также
Деклараторы и объявления переменных
Объявления перечислений C
13.10.2020 • 6 minutes to read • Edit Online

Перечисление состоит из набора именованных целочисленных констант. Объявление типа перечисления


предоставляет имя тега перечисления (необязательно) и определяет набор именованных целочисленных
идентификаторов (называемых "набор перечисления", "константы перечислителя", "перечислители" или
"члены"). Переменная с типом перечисления хранит одно из значений набора перечисления,
определенных этим типом.

Переменные типа enum можно использовать в выражениях индексации и в качестве операндов всех
арифметических операторов и операторов отношения. Перечисления являются альтернативой директиве
препроцессора #define с тем преимуществом, что можно создать значения, подчиняющиеся обычным
правилам области.

В ANSI C выражения, определяющие значение константы перечислителя, всегда имеют тип int . Таким
образом хранилище, связанное с переменной перечисления, является хранилищем, необходимым для
одного значения int . Константу перечисления или значение перечисляемого типа можно использовать
как целочисленное выражение в любом месте, допустимом в языке C.

Синтаксис
enum-specifier:
enum identifier opt { enumerator-list }
enum identifier

Необязательный параметр identifier именует тип перечисления, определенный параметром enumerator-list.


Этот идентификатор часто называется тегом перечисления, определенным списком. Описатель типа

enum identifier
{
enumerator-list
}

объявляет , что identifier является тегом для перечисления, определенного нетерминальным параметром
enumerator-list. enumerator-list определяет содержимое перечислителя. Подробное описание параметра
enumerator-list представлено ниже.
Если объявление тега является видимым, все последующие объявления, в которых используется этот тег,
но отсутствует enumerator-list, обозначают ранее объявленный перечисляемый тип. Тег должен ссылаться
на определенный тип перечисления, и этот тип перечисления должен находиться в текущей области.
Поскольку тип перечисления определен в другом месте, enumerator-list не отображается в этом
объявлении. В объявлениях типов, производных от перечислений, и объявлениях typedef для типов
перечислений можно использовать тег перечисления до определения типа перечисления.

Синтаксис
enumerator-list:
enumerator
enumerator-list , enumerator
enumerator:
enumeration-constant
enumeration-constant = constant-expression
enumeration-constant:
identifier
Каждое значение enumeration-constant в списке enumerator-list именует значение набора перечисления.
По умолчанию первый параметр enumeration-constant связан со значением 0. Следующий параметр
enumeration-constant в списке связывается со значением (enumeration-constant + 1), если явно не указано
другое значение. Имя параметра enumeration-constant эквивалентно его значению.

Можно использовать выражение enumeration-constant = constant-expression для переопределения


используемой по умолчанию последовательности значений. Таким образом, если в списке enumerator-list
встречается выражение enumeration-constant = constant-expression, параметр enumeration-constant
связывается со значением соответствующего выражения constant-expression. Выражение constant-
expression должно иметь тип int и может быть отрицательным.
К членам набора перечисления применяются следующие правила.

Набор перечисления может содержать повторяющиеся постоянные значения. Например, значение 0


можно связать с двумя разными идентификаторами, такими как null и zero , в одном и том же
наборе.

Идентификаторы в списке перечисления должны отличаться от других идентификаторов в той же


области с той же видимостью, включая обычные имена переменных и идентификаторы в других
списках перечисления.

К тегам перечисления применяются обычные правила области. Они должны отличаться от всех
тегов перечислений, структур или объединений с такой же видимостью.

Примеры
В следующих примерах показаны объявления перечисления.

enum DAY /* Defines an enumeration type */


{
saturday, /* Names day and declares a */
sunday = 0, /* variable named workday with */
monday, /* that type */
tuesday,
wednesday, /* wednesday is associated with 3 */
thursday,
friday
} workday;

Значение 0 связано с saturday по умолчанию. Для идентификатора sunday явно задано значение 0.
Оставшимся идентификаторам по умолчанию присваиваются значения от 1 до 5.

В этом примере значение из набора DAY присваивается переменной today .

enum DAY today = wednesday;

Обратите внимание, что имя константы перечисления используется для присвоения значения. Поскольку
тип перечисления DAY был объявлен ранее, необходим только тег перечисления DAY .

Чтобы явно присвоить целочисленное значение переменной перечисляемого типа данных, используйте
следующее приведение типа.
workday = ( enum DAY ) ( day_value - 1 );

Это приведение рекомендовано к использованию в С , но не является обязательным.

enum BOOLEAN /* Declares an enumeration data type called BOOLEAN */


{
false, /* false = 0, true = 1 */
true
};

enum BOOLEAN end_flag, match_flag; /* Two variables of type BOOLEAN */

Это объявление также можно указать как

enum BOOLEAN { false, true } end_flag, match_flag;\

или как

enum BOOLEAN { false, true } end_flag;


enum BOOLEAN match_flag;

Пример, в котором используются эти переменные, может выглядеть следующим образом.

if ( match_flag == false )
{
.
. /* statement */
.
}
end_flag = true;

Также можно объявить неименованные типы данных перечислителя. Имя типа данных опускается, но
можно объявлять переменные. Переменная response является переменной определенного типа.

enum { yes, no } response;

См. также
Перечисления
Объявления структур
13.10.2020 • 8 minutes to read • Edit Online

"Объявление структуры" именует тип и задает последовательность переменных значений ("элементы" или
"поля" структуры), которые могут иметь разные типы. Необязательный идентификатор — тег —
предоставляет имя типа структуры и может использоваться в последующих ссылках на тип структуры.
Переменная этого типа структуры включает определенную этим типом последовательность целиком.
Структуры в языке C аналогичны типам, известным в других языках как "записи".

Синтаксис
спецификатор-структуры-или-объединения:
struct-or-union identifieropt { struct-declaration-list }
struct-or-union identifier
структура-или-объединение:
struct
union

список-объявлений-структуры:
struct-declaration
struct-declaration-list struct-declaration
объявление-структуры:
specifier-qualifier-list struct-declarator-list ;
список-спецификаторов-и-квалификаторов:
type-specifier specifier-qualifier-listopt
type-qualifier specifier-qualifier-listopt
список-деклараторов-структуры:
struct-declarator struct-declarator-list , struct-declarator
декларатор-структуры:
declarator
type-specifier declaratoropt : constant-expression
Объявление типа структуры не оставляет места для структуры. Это всего лишь шаблон для последующих
объявлений структурных переменных.

Ранее определенный идентификатор (тег) можно использовать для ссылки на структурный тип,
определенный в другом месте. В этом случае список-объявлений-структур невозможно повторить, пока
определение видно. Объявления указателей на структуры и объекты typedef для типов структуры могут
использовать тег структуры до определения типа структуры. Однако определение структуры необходимо
получить до выполнения каких-либо фактических действий с размером полей. Это неполное определение
типа и тега типов. Для того чтобы это определение стало полным, определение типа должно
отображаться позже в той же области.

Список-объявлений-структуры задает типы и имена элементов структуры. Аргумент список-объявлений-


структуры содержит одну или несколько переменных или объявлений битовых полей.
Каждая переменная, объявленная в списке-объявлений-структуры, определяется как элемент
структурного типа. Объявления переменных в списке-объявлений-структуры имеет ту же форму, что и
другие объявления переменных, которые обсуждаются в этом разделе, с той разницей, что эти объявления
не могут содержать описатели или инициализаторы класса хранения. Элементы структуры могут
содержать любые типы переменной, кроме типа void , неполного типа или типа функции.

Невозможно объявить элемент так, чтобы он имел тип структуры, в которой отображается. Однако
элемент можно объявить как указатель на структурный тип, в котором он отображается, при условии, что
этот структурный тип имеет тег. Это позволяет создавать связанные списки структур.

Структуры имеют ту же область видимости, что и другие идентификаторы. Идентификаторы структур


должны отличаться от всех тегов структур, объединений и перечислений с той же областью видимости.

Каждое объявление-структуры в списке-объявления-структуры должно быть уникальным в пределах


списка. Однако имена идентификаторов в списке-объявления-структуры не должны отличаться от
стандартных имен переменных или идентификаторов в других списках объявления структуры.

Доступ к вложенным структурам можно осуществлять так же, как если бы они были объявлены на уровне
области файлов. Например, с данным объявлением

struct a
{
int x;
struct b
{
int y;
} var2;
} var1;

оба объявления являются допустимыми:

struct a var3;
struct b var4;

Примеры
В следующих примерах показаны объявления структуры.

struct employee /* Defines a structure variable named temp */


{
char name[20];
int id;
long class;
} temp;

Структура employee содержит три члена: name , id и class . Член name — это 20-элементный массив, а
id и class — простые элементы с типом int и long соответственно. Идентификатор employee
является идентификатором структуры.

struct employee student, faculty, staff;

В этом примере определяются три переменных структуры: student , faculty и staff . Каждая структура
имеет такой же список из трех элементов. Эти элементы объявлены как имеющие структурный тип
employee , определенный в предыдущем примере.
struct /* Defines an anonymous struct and a */
{ /* structure variable named complex */
float x, y;
} complex;

Структура complex содержит два элемента с типом float — x и y . Тип структуры не имеет тегов и,
следовательно, является безымянным или анонимным.

struct sample /* Defines a structure named x */


{
char c;
float *pf;
struct sample *next;
} x;

Первые два элемента структуры — это переменная char и указатель на значение float . Третий элемент ,
next , объявляется как указатель на определяемый структурный тип ( sample ).

Анонимные структуры могут быть полезны, если именованный тег не требуется. Это происходит в том
случае, если одно объявление определяет все экземпляры структуры. Пример:

struct
{
int x;
int y;
} mystruct;

Встроенные структуры часто являются анонимными.

struct somestruct
{
struct /* Anonymous structure */
{
int x, y;
} point;
int type;
} w;

Блок , относящийся только к системам Microsoft

Компилятор позволяет использовать безразмерный массив или массив нулевого размера в качестве
последнего члена структуры. Это полезно, если размер константного массива различается при
использовании в разных ситуациях. Объявление такой структуры выглядит следующим образом.

struct identifier { set-of-declarations type array-name []; };


Безразмерные массивы могут отображаться только в качестве последнего члена структуры. Структуры,
содержащие объявления безразмерных массивов, могут вкладываться в другие структуры при условии, что
никакие другие элементы не объявлены ни в одной из внешних структур. Массивы таких структур
использовать не разрешается. Оператор sizeof , если он применен к переменной этого типа или к самому
типу, предполагает , что размер массива равен 0.

Объявления структуры также можно задать без декларатора, если они являются элементами другой
структуры или объединения. Уровень имен полей повышается до уровня внешней структуры. Например,
безыменная структура выглядит следующим образом:
struct s
{
float y;
struct
{
int a, b, c;
};
char str[10];
} *p_s;
.
.
.
p_s->b = 100; /* A reference to a field in the s structure */

См. справочные сведения о структурах в разделе Элементы структур и объединений.

Завершение блока , относящегося только к системам Майкрософт

См. также
Деклараторы и объявления переменных
Битовые поля в C
13.10.2020 • 4 minutes to read • Edit Online

Представлять собой заданное количество бит , т. е. "битовое поле", могут не только деклараторы для
членов структуры или объединения, но и декларатор структуры. Указание его длины отделяется от
декларатора имени поля двоеточием. Битовое поле интерпретируется как целочисленный тип.

Синтаксис
декларатор-структуры:
declarator
type-specifier declaratoropt : constant-expression
Выражение constant-expression задает ширину поля в битах. type-specifier для declarator должен иметь тип
unsigned int , signed int или int , а значение constant-expression должно быть неотрицательными и
целочисленным. Если указано значение 0, то объявление не содержит declarator . Массивы битовых полей,
указатели на битовые поля, а также функции, возвращающие битовые поля, не допускаются.
Необязательный параметр declarator задает имя битового поля. Битовые поля могут объявляться только в
рамках структуры. Оператор взятия адреса ( & ) не может применяться к компонентам битового поля.

Создавать ссылки на неименованные битовые поля невозможно; их содержимое во время выполнения


непредсказуемо. Их можно использовать в качестве фиктивных полей в целях выравнивания.
Неименованное битовое поле, для которого задана ширина 0, гарантирует , что область хранения для
элемента, который следует за ним в struct-declaration-list, начнется на границе int .

Битовые поля должны иметь достаточную длину, чтобы вмещать в себя битовый шаблон. Например,
следующие два оператора недопустимы.

short a:17; /* Illegal! */


int long y:33; /* Illegal! */

В этом примере определен двумерный массив структур с именем screen .

struct
{
unsigned short icon : 8;
unsigned short color : 4;
unsigned short underline : 1;
unsigned short blink : 1;
} screen[25][80];

Массив содержит 2000 элементов. Каждый элемент представляет собой отдельную структуру с четырьмя
членами, каждый из которых представляет собой битовое поле: icon , color , underline и blink . Размер
каждой структуры равен 2 байтам.

Битовые поля имеют одну и ту же семантику, что и целочисленный тип. Это означает , что битовое поле
используется в выражениях точно так же, как использовалась бы переменная того же базового типа,
независимо от количества битов в битовом поле.

Блок , относящийся только к системам Microsoft

Битовые поля, определенные как int , обрабатываются как signed . Расширение Microsoft к стандарту ANSI
C допускает битовые поля типов char и long (как signed , так и unsigned ). Неименованные битовые поля
с базовым типом long , short или char ( signed или unsigned ) принудительно устанавливают
выравнивание по границе, соответствующей этому типу.

Битовые поля в целом числе назначаются в направлении от младшего разряда к старшему. В приведенном
ниже коде

struct mybitfields
{
unsigned short a : 4;
unsigned short b : 5;
unsigned short c : 7;
} test;

int main( void );


{
test.a = 2;
test.b = 31;
test.c = 0;
}

биты размещаются следующим образом:

00000001 11110010
cccccccb bbbbaaaa

Поскольку в процессорах семейства 8086 младший байт целочисленных значений размещается перед
старшим байтом, указанное выше целое число 0x01F2 будет храниться в физической памяти как 0xF2 , за
которым следует 0x01 .

Завершение блока , относящегося только к системам Майкрософт

См. также
Объявления структур
Хранение и выравнивание структур
13.10.2020 • 3 minutes to read • Edit Online

Блок , относящийся только к системам Microsoft

Структурные элементы сохраняются последовательно, в порядке объявления: первый элемент имеет самый
низкий адрес памяти, а последний — наивысший.

У каждого объекта есть элемент alignment-requirement. Для структур таким требованием является
крупнейший из элементов таких структур. Каждому объекту задается элемент offset, чтобы было верно
следующее выражение:

offset % alignment-requirement == 0
Смежные битовые поля упакованы в тот же одно-, двух- или четырехбайтовый модуль распределения, если
целочисленные типы имеют тот же размер и если следующее битовое поле помещается в текущий блок
распределения, не пересекая границ, установленных общими требованиями выравнивания битовых полей.

Для экономии места или соответствия существующим структурам данных может потребоваться сохранить
структуры более или менее компактно. Параметр компилятора /Zp[n] и #pragma pack управляют упаковкой
данных структуры в память. При использовании параметра /Zp[n], где n — 1, 2, 4, 8 или 16, каждый элемент
структуры после первого хранится в байтовом диапазоне, который представляет собой требование к
выравниванию поля или размер пакета (n) в зависимости от того, что меньше. В виде формулы байтовые
границы можно выразить следующим образом:

min( n, sizeof( item ) )

где n — это размер пакета, выраженный с параметром /Zp[n], а item — это элемент структуры. Размер
пакета по умолчанию — /Zp8.

Чтобы использовать директиву pragma pack для указания упаковки, отличной от заданной в командной
строке для определенной структуры, разместите директиву pragma pack , где размер пакета — 1, 2, 4, 8 или
16, перед структурой. Для возобновления компоновки в соответствии с инструкциями с командной строки
задайте директиву pragma pack без аргументов.

Битовые поля по умолчанию имеют размер long для компилятора Microsoft C. Элементы структуры
выравниваются по размеру типа или размеру /Zp [n] в зависимости от того что меньше. Размер по
умолчанию — 4.

Завершение блока , относящегося только к системам Майкрософт

См. также
Объявления структур
Объявления объединений
13.10.2020 • 4 minutes to read • Edit Online

Объявление объединения определяет набор значений переменных и при необходимости тег, который
именует объединение. Значения переменных называются членами объединения и могут иметь различные
типы. Объединения аналогичны вариантным записям в других языках.

Синтаксис
спецификатор-структуры-или-объединения:
struct-or-union identifieropt { struct-declaration-list }
struct-or-union identifier
структура-или-объединение:
struct
union

список-объявлений-структуры:
struct-declaration
struct-declaration-list struct-declaration
Содержимое объединения определено как

объявление-структуры:
specifier-qualifier-list struct-declarator-list ;
список-спецификаторов-и-квалификаторов:
type-specifier specifier-qualifier-listopt
type-qualifier specifier-qualifier-listopt
список-деклараторов-структуры:
struct-declarator
struct-declarator-list , struct-declarator
Переменная с типом union хранит одно из значений, определенных в этом типе. Объявления структуры и
объединения подчиняются тем же правилам. Объединения также могут иметь битовые поля.

Элементы объединений не могут иметь неполный тип, тип void или тип функции. Поэтому члены могут
быть указателями на объявляемый тип объединения, но не экземпляром объединения.

Объявление типа объединения — это лишь шаблон. Память не резервируется, пока не будет объявлена
переменная.

NOTE
Если объявляется объединение двух типов и сохраняется одно значение, но для доступа к объединению
используется другой тип, результаты будут ненадежными. Например, объявлено объединение float и int .
Сохраняется значение float , но программа позднее использует это значение как int . В таком случае
полученное значение будет зависеть от внутренних хранимых данных для значений float . Целочисленное
значение будет ненадежным.

Примеры
Ниже представлены примеры объединений.

union sign /* A definition and a declaration */


{
int svar;
unsigned uvar;
} number;

В этом примере определяется переменная объединения с типом sign и объявляется переменная number с
двумя членами: целым числом со знаком svar и целым числом без знака uvar . В результате этого
объявления можно сохранить текущее значение number как целое число со знаком или целое число без
знака. С данным типом объединения связан тег sign .

union /* Defines a two-dimensional */


{ /* array named screen */
struct
{
unsigned int icon : 8;
unsigned color : 4;
} window1;
int screenval;
} screen[25][80];

Массив screen содержит 2000 элементов. Каждый элемент массива представляет собой отдельное
объединение с двумя членами: window1 и screenval . Член window1 является структурой с двумя членами-
битовыми полями: icon и color . Элемент screenval представляет собой int . В любой момент времени
каждый элемент объединения содержит значение int , представленное screenval , либо структуру,
представленную значением window1 .

Блок , относящийся только к системам Microsoft

Вложенные объединения можно объявить анонимно, если они являются членами другой структуры или
объединения. Ниже приводится пример безымянного объединения.

struct str
{
int a, b;
union / * Unnamed union */
{
char c[4];
long l;
float f;
};
char c_array[10];
} my_str;
.
.
.
my_str.l == 0L; /* A reference to a field in the my_str union */

Объединения часто являются вложенными в структуре, содержащей поле, ко