Вы находитесь на странице: 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 */

Объединения часто являются вложенными в структуре, содержащей поле, которое представляет тип
данных, содержащихся в объединении в определенный момент времени. Ниже приводится пример
объявления такого объединения.
struct x
{
int type_tag;
union
{
int x;
float y;
}
}

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

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

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

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

union /* Defines a union named x */


{
char *a, b;
float f[20];
} x;

Элементы объединения x являются (в порядке их объявления) указателями на значение типа char ,


значение типа char и массив значений типа float . Хранилище, выделенное для x , — это хранилище,
необходимое для массива f , состоящего из 20 элементов, поскольку f является самым длинным членом
объединения. Так как ни один тег не связан с объединением, его тип является безымянным или анонимным.

См. также
Объявления объединений
Объявления массивов
13.10.2020 • 4 minutes to read • Edit Online

"Объявление массива" именует массив и задает тип его элементов. Он также может определять число
элементов в массиве. Переменная с типом массива считается указателем на тип элементов массива.

Синтаксис
declaration:
declaration-specifiers init-declarator-listopt ;
init-declarator-list:
init-declarator
init-declarator-list , init-declarator
init-declarator:
declarator
declarator = initializer
declarator:
pointeropt direct-declarator
direct-declarator: /* Декларатор функции */
direct-declarator [ constant-expressionopt ]
Так как значение constant-expression является необязательным, этот синтаксис имеет две формы:

Первая форма определяет переменную массива. Аргумент constant-expression в квадратных скобках


задает число элементов в массиве. Аргумент constant-expression (при наличии) должен иметь
целочисленный тип и значение больше нуля. Каждый элемент имеет тип, заданный с помощью type-
specifier, который может быть любым типом, кроме void . Элемент массива не может являться
типом функции.

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

В обеих формах direct-declarator именует переменную и может изменить тип переменной. Квадратные
скобки ( [ ] ) после direct-declarator изменяют декларатор на тип массива.

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


применяются к элементам, а не самому массиву.

Можно объявить массив массивов (многомерный массив), поместив после декларатора массива список
константных выражений в квадратных скобках в следующем виде:

type-specifier declarator [ constant-expression ] [ constant-expression ] ...

Каждый аргумент constant-expression в квадратных скобках указывает число элементов в определенном


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

Можно определить массивы указателей на различные типы объектов с помощью сложных деклараторов,
как описано в разделе Interpreting More Complex Declarators (Интерпретация более сложных
деклараторов).

Массивы сохраняются по строкам. Например, следующий массив состоит из двух строк по три столбца
каждая.

char A[2][3];

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

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

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

float matrix[10][15];

Двумерный массив с именем matrix включает 150 элементов, каждый из которых относится к типу float .

struct {
float x, y;
} complex[100];

Это объявление массива структур. Этот массив содержит 100 элементов, каждый элемент — это
структура, содержащая два члена.

extern char *name[];

Эта инструкция объявляет тип и имя массива указателей как char . Фактическое определение name
происходит в другом месте.

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

Тип целого числа, необходимый для удержания максимального размера массива, — это размер size_t .
Определенный в файле заголовка STDDEF.H параметр size_t представляет собой значение типа
unsigned int с диапазоном от 0x00000000 до 0x7CFFFFFF.

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

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

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

См. также
Объявления массивов
Объявления указателей
13.10.2020 • 6 minutes to read • Edit Online

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

Синтаксис
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
type-specifier предоставляет тип объекта, который может являться любым базовым, структурным типом
или типом объединения. Переменные указателя также могут указывать на функции, массивы и другие
указателям. (Дополнительные сведения об объявлении и интерпретации более сложных типов указателей
см. в разделе Интерпретация более сложных деклараторов.)

Создав type-specifier типа void , можно отложить спецификацию типа, к которой относится указатель.
Этот элемент называется "указатель на void " и записывается как void * . Переменная, объявленная как
указатель на void, может использоваться для указания на объект любого типа. Однако для того чтобы
выполнять большинство операций с указателем или объектом, на который он указывает , тип, на который
он указывает , должен быть явно задан для каждой операции. (Переменные типа char * и void * могут
присваиваться без приведения типа.) Такое преобразование можно выполнить с помощью приведения
типа (дополнительные сведения см. в разделе Преобразования с приведением типа).

type-qualifier может иметь значение const или volatile , либо и то, и другое. Они, соответственно,
указывают , что указатель не может быть изменен самой программой ( const ) или что указатель может
быть изменен каким-либо неподконтрольным программе процессом ( volatile ). Дополнительные
сведения о ключевых словах const и volatile см. в статье Квалификаторы типов.

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

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

char *message; /* Declares a pointer variable named message */

Указатель message указывает на переменную типа char .

int *pointers[10]; /* Declares an array of pointers */

Массив pointers содержит 10 элементов; каждый элемент имеет указатель на переменную с типом int .

int (*pointer)[10]; /* Declares a pointer to an array of 10 elements */

Переменная pointer указывает на массив с 10 элементами. Каждый элемент в этом массиве имеет тип int .

int const *x; /* Declares a pointer variable, x,


to a constant value */

Указатель x можно изменить, чтобы он указывал на другое значение int но значение, на которое он
указывает , изменить невозможно.

const int some_object = 5 ;


int other_object = 37;
int *const y = &fixed_object;
int volatile *const z = &some_object;
int *const volatile w = &some_object;

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


Значение, на которое он указывает , можно изменить, но указатель должен всегда указывать на одно и то
же расположение — адрес fixed_object. Аналогично z — это постоянный указатель, но он также
объявляется таким образом, чтобы указывать на int , значение которого невозможно преобразовать
программой. Дополнительный описатель volatile указывает , что хотя значение const int , на которое
указывает z, невозможно изменить программой, его можно изменить процессом, выполняемым
одновременно с программой. Объявление w указывает , что программа не может изменить значение, на
которое указывает указатель, и что программа не может изменить сам указатель.

struct list *next, *previous; /* Uses the tag for list */

В этом примере объявляются две переменные указателя, next и previous, указывающие на структурный тип
list. Это объявление может отображаться перед определением структурного типа list (см. следующий
пример), если определение типа list имеет ту же видимость, что и объявление.

struct list
{
char *token;
int count;
struct list *next;
} line;

Переменная line имеет структурный тип с именем list. Тип структуры list содержит три элемента: указатель
на значение типа char , значение типа int и указатель на другую структуру list.

struct id
{
unsigned int id_no;
struct name *pname;
} record;

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

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

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

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

Для компилятора Microsoft C значение sizeof(char *) равно значению sizeof(int *) .

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

См. также
Объявления указателей
Основанные указатели (C)
13.10.2020 • 2 minutes to read • Edit Online

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

__based (Справочник по C ++)


В 32- и 64-разрядных компиляторах Microsoft базовый указатель является 32- или 64-разрядным смещением
от 32- или 64-разрядной базы указателя. Базовая адресация полезна для управления разделами, в которых
размещены объекты, поскольку уменьшается размер исполняемого файла и увеличивается скорость
выполнения. Как правило, используется следующая форма определения относительного указателя.

type __based( base ) declarator

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


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

Указатели на основе указателей, в частности, используются для постоянных идентификаторов, которые


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

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

void *vpBuffer;

struct llist_t
{
void __based( vpBuffer ) *vpData;
struct llist_t __based( vpBuffer ) *llNext;
};

Указателю vpBuffer назначается адрес в памяти, который выделяется на более позднем этапе программы.
Связанный список перемещается относительно значения vpBuffer .

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

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

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

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

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

int * // The type name for a pointer to type int:

int *[3] // An array of three pointers to int

int (*) [5] // A pointer to an array of five int

int *() // A function with no parameter specification


// returning a pointer to int

// A pointer to a function taking no arguments and


// returning an int

int (*) ( void )

// An array of an unspecified number of constant pointers to


// functions each with one parameter that has type unsigned int
// and an unspecified number of other parameters returning an int

int (*const []) ( unsigned int, ... )

NOTE
Абстрактный декларатор не может состоять из набора пустых скобок, ( ) , поскольку такая запись является
неоднозначной. Невозможно определить, принадлежит ли неявный идентификатор области внутри скобок (и
является в этом случае неизмененным типом) или перед скобками (и является в этом случае типом функции).

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

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

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

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

1. Начните с идентификатора и найдите ближайшие квадратные или круглые скобки справа от него
(если есть).
2. Интерпретируйте эти квадратные или круглые скобки, затем найдите звездочку слева.
3. Если на каком-либо шаге обнаружится правая круглая скобка, перейдите назад и примените
правила 1 и 2 ко всему выражению в круглых скобках.

4. Примените спецификатор типа.

char *( *(*var)() )[10];


^ ^ ^ ^ ^ ^ ^
7 6 4 2 1 3 5

В этом примере шаги пронумерованы по порядку и интерпретируются следующим образом:

1. Идентификатор var объявлен как

2. указатель на
3. функцию, возвращающую
4. указатель на
5. массив из 10 элементов, которые являются
6. указателями на
7. значения типа char .

Примеры
В следующих примерах приведены другие сложные объявления и показано, как круглые скобки могут
влиять на значение объявления.
int *var[5]; /* Array of pointers to int values */

Модификатор массива имеет более высокий приоритет , чем модификатор указателя, поэтому переменная
var объявляется как массив. Модификатор указателя применяется к типу элементов массива;
следовательно, элементы массива являются указателями на значения типа int .

int (*var)[5]; /* Pointer to array of int values */

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

long *var( long, long ); /* Function returning pointer to long */

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

long (*var)( long, long ); /* Pointer to function returning long */

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

struct both /* Array of pointers to functions */


{ /* returning structures */
int a;
char b;
} ( *var[5] )( struct both, struct both );

Элементы массива не могут быть функциями, но это объявление показывает , как объявить массив
указателей на функции. В данном примере переменная var объявляется как массив из 5 указателей на
функции, возвращающие структуры с двумя членами. В качестве аргументов для функций объявлены две
структуры с тем же типом структуры, both . Обратите внимание, что скобки вокруг *var[5] обязательны.
Без них объявление было бы недопустимой попыткой объявить массив функций, как показано ниже:

/* ILLEGAL */
struct both *var[5](struct both, struct both);

Следующий оператор объявляет массив указателей.

unsigned int *(* const *name[5][10] ) ( void );

Массив name содержит 50 элементов, организованных в многомерный массив. Элементы являются


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

В следующем примере показана функция, возвращающая указатель на массив из трех значений типа
double .
double ( *var( double (*)[3] ) )[3];

В этом объявлении функция возвращает указатель на массив, поскольку функции не могут возвращать
массивы. Здесь переменная var объявлена как функция, возвращающая указатель на массив из трех
значений типа double . Функция var принимает один аргумент. Аргумент , как и возвращаемое значение,
является указателем на массив из трех значений типа double . Тип аргумента задан сложным
абстрактным декларатором abstract-declarator. Скобки вокруг звездочки в типе аргумента обязательны.
Без них аргумент будет иметь тип массива из трех указателей на значения типа double . Обсуждение и
примеры абстрактных деклараторов см. в статье Абстрактные деклараторы.

union sign /* Array of arrays of pointers */


{ /* to pointers to unions */
int x;
unsigned y;
} **var[5][5];

Как показано в приведенном выше примере, указатель может указывать на другой указатель, и массив
может содержать элементы, являющиеся массивами. Здесь переменная var представляет собой массив
из 5 элементов. Каждый элемент представляет собой 5-элементный массив указателей на объединения с
двумя членами.

union sign *(*var[5])[5]; /* Array of pointers to arrays


of pointers to unions */

В этом примере показано, как круглые скобки изменяют значение объявления. В этом примере
переменная var является 5-элементным массивом указателей на 5-элементные массивы указателей на
объединения. Примеры применения typedef для исключения сложных объявлений см. в статье
Объявления Typedef.

См. также
Объявления и типы
Инициализация
07.05.2020 • 2 minutes to read • Edit Online

"Инициализатор" представляет собой значение или последовательность значений, присваиваемых


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

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


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

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

При инициализации скалярных типов значение assignment-expression присваивается переменной.


Применяются правила преобразования для присваивания. (См. сведения о правилах преобразования в
статье Преобразования типов (C).)

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

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 /* Для инициализации скалярных типов */
initializer :
assignment-expression

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

Переменные, объявленные на уровне области файлов, можно инициализировать. Если явно не


инициализировать переменную на внешнем уровне, она инициализируется значением 0 по
умолчанию.

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


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

Переменные, объявленные с описателем класса хранения auto или register , инициализируются


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

Начальные значения для объявлений внешних переменных и для всех переменных static (как
внешних, так и внутренних) должны представлять собой константные выражения. (Дополнительные
сведения см. в разделе Постоянные выражения в C.) Так как адрес объявленной внешне или
статической переменной является константным, его можно использовать для инициализации
объявленной внутренне переменной указателя static . Но адрес переменной auto невозможно
использовать как статический инициализатор, так как он может быть разным для каждого
исполнения блока. Для инициализации переменных auto и register можно использовать
константные или переменные значения.

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

Примеры
Инициализация иллюстрируется следующими примерами.

int x = 10;

Целочисленная переменная x инициализируется с константным выражением 10 .

register int *px = 0;

Указатель px инициализируется значением 0, создавая указатель null.

const int c = (3 * 1024);

В этом примере константное выражение (3 * 1024) используется для инициализации c с константным


значением, которое невозможно изменить из-за ключевого слова const .

int *b = &x;

Этот оператор инициализирует указатель b адресом другой переменной, x .

int *const a = &z;

Указатель a инициализируется с адресом переменной с именем z . Но так как он определен как const ,
переменную a можно только инициализировать, но не изменить. Она всегда указывает на одно и то же
расположение.

int GLOBAL ;

int function( void )


{
int LOCAL ;
static int *lp = &LOCAL; /* Illegal initialization */
static int *gp = &GLOBAL; /* Legal initialization */
register int *rp = &LOCAL; /* Legal initialization */
}

Глобальная переменная GLOBAL объявляется на внешнем уровне и поэтому имеет глобальное время
существования. Локальная переменная LOCAL относится к классу хранения auto , и адрес у нее есть только
во время исполнения функции, в которой она объявлена. Поэтому инициализировать переменную
указателя static lp с использованием адреса LOCAL невозможно. Переменную указателя static gp
можно инициализировать с использованием адреса GLOBAL , так как он всегда остается неизменным.
Аналогично, *rp можно инициализировать, так как переменная rp является локальной и может иметь
неконстантный инициализатор. Всякий раз при входе в блок LOCAL имеет новый адрес, который затем
присваивается rp .

См. также
Инициализация
Инициализация агрегатных типов
13.10.2020 • 9 minutes to read • Edit Online

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

Синтаксис
initializer:
{ initializer-list } /* Для агрегатной инициализации */
{ initializer-list , }
initializer-list:
initializer
initializer-list , initializer
Параметр initializer-list содержит список инициализаторов, разделенных запятыми. Каждый инициализатор
в списке является константным выражением или списком инициализаторов. Поэтому списки
инициализаторов могут быть вложенными. Эта форма полезна для инициализации агрегатных членов
агрегатного типа, как показано в примерах этого раздела. Однако если инициализатор для
автоматического идентификатора является одним выражением, оно не обязательно должно быть
константным; достаточно, чтобы выражение имело соответствующий тип для назначения идентификатору.

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


членам агрегатной переменной по порядку.

Если initializer-list имеет меньше значений, чем агрегатный тип, оставшиеся члены или элементы
агрегатного типа инициализируются значением 0. Начальное значение автоматического идентификатора,
которое не инициализировано явно, не определено. Если initializer-list имеет больше значений, чем
агрегатный тип, выдается ошибка. Эти правила применяются к каждому внедренному списку
инициализаторов, а также к агрегату в целом.

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

При инициализации объединения параметр initializer-list должен быть одним константным выражением.
Значение константного выражения присваивается первому члену объединения.

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

Обратите внимание, что количество инициализаторов может задать размер массива.

int x[ ] = { 0, 1, 2 }

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

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

Максимальный размер массива определяется параметром size_t . Определенный в файле заголовка


STDDEF.H параметр size_t представляет собой значение типа unsigned int с диапазоном от 0x00000000 до
0x7CFFFFFF.
Завершение блока , относящегося только к системам Майкрософт

Примеры
В следующем примере представлены инициализаторы массива.

int P[4][3] =
{
{ 1, 1, 1 },
{ 2, 2, 2 },
{ 3, 3, 3,},
{ 4, 4, 4,},
};

Этот оператор объявляет P как массив, состоящий из трех строк и четырех столбцов, и инициализирует
элементы первой строки значением 1, элементы второй строки — значением 2 и т. д. до четвертой строки.
Обратите внимание, что список инициализаторов для третьей и четвертой строк содержит запятые после
последнего константного выражения. За последним списком инициализаторов ( {4, 4, 4,}, ) также следует
запятая. Эти дополнительные запятые являются допустимыми, но не обязательными; обязательными
являются только запятые, которые отделяют одно константное выражение от другого, и запятые, которые
отделяют один список инициализаторов от другого.

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

int P[4][3] =
{
1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4
};

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

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


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

typedef struct
{
int n1, n2, n3;
} triplet;

triplet nlist[2][3] =
{
{ { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }, /* Row 1 */
{ { 10,11,12 }, { 13,14,15 }, { 16,17,18 } } /* Row 2 */
};

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

1. Первая открывающая фигурная скобка в строке 1 сообщает компилятору, что начинается


инициализация первого агрегатного члена nlist (то есть nlist[0] ).
2. Вторая открывающая фигурная скобка указывает , что начинается инициализация первого
агрегатного члена nlist[0] (то есть структуры nlist[0][0] ).

3. Первая закрывающая фигурная скобка завершает инициализацию структуры nlist[0][0] .


Следующая открывающая фигурная скобка начинает инициализацию nlist[0][1] .
4. Процесс будет продолжать до конца строки, где последняя закрывающая фигурная скобка завершит
инициализацию nlist[0] .

Строка 2 присваивает значения второй строке nlist аналогичным образом. Обратите внимание, что
требуются внешние пары фигурных скобок, в которые будут заключены инициализаторы в строках 1 и 2. В
следующей конструкции внешние фигурные скобки отсутствуют , и это привело бы к ошибке.

triplet nlist[2][3] = /* THIS CAUSES AN ERROR */


{
{ 1, 2, 3 },{ 4, 5, 6 },{ 7, 8, 9 }, /* Line 1 */
{ 10,11,12 },{ 13,14,15 },{ 16,17,18 } /* Line 2 */
};

В этой конструкции первая открывающая фигурная скобка в строке 1 запускает инициализацию nlist[0] ,
который является массивом из трех структур. Значения 1, 2 и 3 присваиваются трем членам первой
структуры. При обнаружении следующей закрывающей фигурной скобки (после значения 3)
инициализация nlist[0] завершается, и две оставшиеся структуры в массиве из трех структур
автоматически инициализируются значением 0. Аналогичным образом { 4,5,6 } инициализирует первую
структуру во второй строке nlist . Оставшимся двум структурам nlist[1] присваивается значение 0. Когда
компилятор обнаруживает следующий список инициализаторов ( { 7,8,9 } ), он выполняет попытку
инициализировать nlist[2] . Поскольку nlist имеет только две строки, эта попытка завершится с
ошибкой.

В следующем примере три элемента x с типом int инициализируются значениями 1, 2 и 3


соответственно.

struct list
{
int i, j, k;
float m[2][3];
} x = {
1,
2,
3,
{4.0, 4.0, 4.0}
};

В структуре list выше три элемента в первой строке m инициализируются значением 4,0; элементы
оставшейся части строки m инициализируются значением 0,0 по умолчанию.

union
{
char x[2][3];
int i, j, k;
} y = { {
{'1'},
{'4'}
}
};
В данном примере инициализируется переменная объединения y . Первый элемент объединения — это
массив, поэтому инициализатор является агрегатным инициализатором. Список инициализаторов {'1'}
присваивает значения первой строке массива. Поскольку только одно значение отображается в списке,
элемент в первом столбце инициализируется символом 1 , а оставшиеся два элемента в строке
инициализируются значением 0 по умолчанию. Аналогичным образом, первый элемент второй строки x
инициализируется символом 4 , а оставшиеся два элемента в строке инициализируются значением 0.

См. также
Инициализация
Инициализация строк
07.05.2020 • 2 minutes to read • Edit Online

Массив символов (или расширенных символов) можно инициализировать со строковым литералом (или
расширенным строковым литералом). Пример:

char code[ ] = "abc";

Этот код инициализирует символьный массив code с четырьмя элементами. Четвертым элементом
является символ null, которым завершаются все строковые литералы.

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

char code[3] = "abcd";

Массиву code присваиваются только первые три символа инициализатора. Символ d и символ null,
завершающий строки, отбрасываются. Обратите внимание, что при этом будет создана незавершенная
строка (т. е. строка без значения 0, которым обозначается ее конец) и сгенерировано диагностическое
сообщение, указывающее на это состояние.

Объявление

char s[] = "abc", t[3] = "abc";

идентично объявлению

char s[] = {'a', 'b', 'c', '\0'},


t[3] = {'a', 'b', 'c' };

Если строка короче указанного размера массива, то остальные элементы массива инициализируются как
равные 0.

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

В Microsoft C строковые литералы могут иметь длину до 2048 байт.

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

См. также
Инициализация
Хранилище базовых типов
13.10.2020 • 2 minutes to read • Edit Online

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

Размеры основных типов


TYPE ХРАНИЛИЩЕ

char , unsigned char , signed char 1 байт

short , unsigned short 2 байта

int , unsigned int 4 байта

long , unsigned long 4 байта

long long , unsigned long long 8 байт

float 4 байта

double 8 байт

long double 8 байт

Типы данных C разделяются на общие категории. Целочисленные типы включают в себя int , char ,
short , long и long long . Такие типы могут иметь уточнение signed или unsigned , а unsigned можно
использовать как краткую форму unsigned int . Типы перечислений ( enum ) также в большинстве
случаев обрабатываются как целочисленные типы. К типам с плавающей запятой относятся float ,
double и long double . Арифметические типы включают все целочисленные типы и типы с плавающей
запятой.

См. также
Объявления и типы
Тип char
13.10.2020 • 2 minutes to read • Edit Online

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

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

Значения символов типа unsigned char находятся в диапазоне от 0 до 0xFF по шестнадцатеричной системе
счисления. signed char имеет диапазон от 0x80 до 0x7F. Эти диапазоны преобразуются в диапазоны от 0 до
255 и от -128 до +127 по десятичной системе счисления соответственно. Параметр компилятора /J
указывает , что вместо signed по умолчанию будет использоваться тип unsigned .

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

См. также
Хранение базовых типов
Тип int
13.10.2020 • 2 minutes to read • Edit Online

Размер знакового или беззнакового элемента signed int или unsigned int соответствует стандартному
размеру целочисленного значения на конкретном компьютере. Например, в 16-разрядных операционных
системах тип int обычно имеет размер 16 бит , или 2 байта. В 32-разрядных операционных системах тип
int обычно имеет размер 32 бита, или 4 байта. Таким образом в зависимости от целевой среды тип int
эквивалентен типу short int или long int , а тип unsigned int — типу unsigned short или unsigned long .
Все типы int представляют знаковые значения, если не указано иное.

Описатели типа int и unsigned int (или просто unsigned ) определяют некоторые функции языка C
(например, тип enum ). В таких случаях определения int и unsigned int для конкретной реализации
определяют фактическую область хранения.

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

Знаковые целочисленные типы представлены в форме дополнительного кода. В старшем бите содержится
следующий знак: 1 означает отрицательные числа, 0 — положительные числа и ноль. Диапазон значений
описывается в статье Пределы целых чисел в C и C++. Пределы определены в файле заголовка LIMITS.H.

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

NOTE
Описатели типов int и unsigned int широко используются в программах на языке C, поскольку они позволяют
обрабатывать целочисленные значения наиболее эффективным на конкретном компьютере способом. Однако
поскольку размеры типов int и unsigned int различаются, программы, которые зависят от конкретного
размера int , не могут переноситься на другие компьютеры. Чтобы программы лучше переносились, вместо
жестко заданных размеров данных можно использовать выражения с оператором sizeof (см. статью Оператор
sizeof ).

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

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

В Microsoft C поддерживаются целочисленные типы с указанием размера. Это позволяет объявлять 8-, 16-,
32- и 64-разрядные целочисленные переменные при помощи описателя типа __intN (где N означает
размер целочисленной переменной в битах). Таким образом, n может иметь значение 8, 16, 32 или 64. В
следующем примере объявляется по одной переменной каждого из 4 целочисленных типов с указанием
размера:

__int8 nSmall; // Declares 8-bit integer


__int16 nMedium; // Declares 16-bit integer
__int32 nLarge; // Declares 32-bit integer
__int64 nHuge; // Declares 64-bit integer

Первые три целочисленных типа с указанием размера являются аналогами типов ANSI, имеющих такой же
размер. Они полезны для написания переносимого кода, который одинаково выполняется на различных
платформах. Тип данных __int8 аналогичен типу char , __int16 — типу short , __int32 — типу int , а
__int64 — типу long long .

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

См. также
Хранение базовых типов
Тип float
07.05.2020 • 6 minutes to read • Edit Online

Числа с плавающей запятой используют формат IEEE (Института инженеров по электротехнике и


электронике). Значения с одиночной точностью и типом float имеют 4 байта, состоят из бита знака, 8-
разрядной двоичной экспоненты excess-127 и 23-битной мантиссы. Мантисса представляет число от 1,0 до
2,0. Поскольку бит высокого порядка мантиссы всегда равен 1, он не сохраняется в числе. Это
представление обеспечивает для типа float диапазон примерно от 3,4E–38 до 3,4E+38.

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

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


TYPE ЗНАЧИМЫЕ ЦИФРЫ ЧИСЛО БАЙТОВ

float 6–7 4

double 15–16 8

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


экспонентой, которая содержит порядок возрастания числа.

В следующей таблице показано количество битов, выделенных мантиссе и экспоненте для каждого типа с
плавающей запятой. Наиболее значимый бит любого типа float или double — всегда бит знака. Если он
равен 1, число считается отрицательным; в противном случае — положительным.

Длина экспонент и мантисс


TYPE ДЛИНА ЭКСПОНЕНТЫ ДЛИНА МАНТИССЫ

float 8 бит 23 бита

double 11 бит 52 бита

Поскольку экспоненты хранятся в форме без знака, экспоненты смещены на половину своего возможного
значения. Для типа float смещение составляет 127; для типа double это 1023. Можно вычислить
фактическое значение экспоненты, вычтя значение смещения из значения экспоненты.

Мантисса хранится в виде бинарной доли, которая больше или равна 1 и меньше 2. Для типов float и double в
мантиссе подразумевается наличие начального 1 в наиболее значимой битовой позиции, поэтому
фактически длина мантисс составляет 24 и 53 бит соответственно, даже если наиболее значимый бит
никогда не хранится в памяти.

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

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


переменных каждого типа с плавающей запятой. Значения, указанные в этой таблице, применяются только
к нормализованным числам с плавающей запятой; денормализованные числа с плавающей запятой имеют
меньшее минимальное значение. Обратите внимание, что номера, сохраненные в регистрах 80x87, всегда
представлены в 80-разрядной нормализованной форме; при сохранении в 32- или 64-разрядных
переменных с плавающей запятой числа могут быть представлены только в ненормализованной форме
(переменные типов float и long).
Диапазон типов с плавающей запятой
TYPE МИНИМАЛЬНОЕ ЗНАЧЕНИЕ МАКСИМАЛЬНОЕ ЗНАЧЕНИЕ

плавающее 1,175494351 E – 38 3,402823466 E + 38

double 2,2250738585072014 E – 308 1,7976931348623158 E + 308

Если точность менее важна, чем размер хранимых данных, имеет смысл использовать тип float для
переменных с плавающей запятой. И наоборот , если точность — наиболее важный критерий, используйте
тип double.

Уровень переменных с плавающей запятой можно повысить до типа большей значимости (преобразование
типа float в тип double). Повышение уровня часто происходит при выполнении арифметических действий с
переменными плавающего типа. Это арифметическое действие всегда выполняется на том же уровне
точности, что и переменная с наивысшим уровнем точности. Например, проанализируйте объявления
следующих типов.

float f_short;
double f_long;
long double f_longer;

f_short = f_short * f_long;

В предыдущем примере уровень переменной f_short повышается до типа double, а затем переменная
умножается на f_long ; затем результат округляется до типа float и присваивается объекту f_short .

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


выполняется на уровне точности переменной типа float (32-разрядной). Уровень результата затем
повышается до уровня double.

f_longer = f_short * f_short;

См. также
Хранение базовых типов
Тип double
07.05.2020 • 2 minutes to read • Edit Online

Значения типа double с двойной точностью имеют размер 8 байт. Формат напоминает формат чисел с
плавающей запятой, за исключением того, что он имеет 11-разрядную экспоненту (ее значение может
превышать 1023) и 52-разрядную мантиссу, а также еще один старший разряд. Значения типа double в этом
формате могут находиться в диапазоне примерно от 1,7E–308 до 1,7E+308.

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

Тип double представлен 64 битами: 1 для знака, 11 для экспоненты и 52 для мантиссы. Он имеет диапазон
+/–1,7E308 с точностью не менее 15 знаков.
Завершение блока , относящегося только к системам Майкрософт

См. также
Хранение базовых типов
Тип long double
13.10.2020 • 2 minutes to read • Edit Online

Тип long double идентичен типу double.

См. также
Хранение базовых типов
Неполные типы
13.10.2020 • 2 minutes to read • Edit Online

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

Тип структуры, для которой еще не были определены члены.

Тип объединения для которого еще не были определены члены.

Тип массива, для которого еще не были определены размерности.

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

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

struct student *ps;

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

struct student
{
int num;
} /* student structure now completed */

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

char a[]; /* a has incomplete type */

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

char a[25]; /* a now has complete type */

См. также
Объявления и типы
Объявления Typedef
13.10.2020 • 5 minutes to read • Edit Online

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

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

Синтаксис
declaration:
declaration-specifiers init-declarator-listopt ;
declaration-specifiers:
storage-class-specifier declaration-specifiersopt
type-specifier declaration-specifiersopt
type-qualifier declaration-specifiersopt
storage-class-specifier:
typedef

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

Имена Typedef используют то же пространство имен, что и обычные идентификаторы (дополнительные


сведения см. в статье Пространства имен). Поэтому в программе может присутствовать имя typedef и
идентификатор с тем же именем в локальной области. Пример:
typedef char FlagType;

int main()
{
}

int myproc( int )


{
int FlagType;
}

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

typedef char FlagType;


const FlagType x;

Чтобы повторно использовать имя FlagType для идентификатора, члена структуры или члена
объединения, необходимо указать тип:

const int FlagType; /* Type specifier required */

Недостаточно написать

const FlagType; /* Incomplete specification */

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

int; /* Illegal declaration */

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

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

typedef void fv( int ), (*pfv)( int ); /* typedef declarations */

void ( *signal( int, void (*) (int)) ) ( int );


fv *signal( int, fv * ); /* Uses typedef type */
pfv signal( int, pfv ); /* Uses typedef type */

Примеры
В следующих примерах показаны объявления typedef:
typedef int WHOLE; /* Declares WHOLE to be a synonym for int */

Обратите внимание, что теперь имя WHOLE может использоваться в объявлении переменных, например
WHOLE i; или const WHOLE i; . Однако объявление long WHOLE i; недопустимо.

typedef struct club


{
char name[30];
int size, year;
} GROUP;

Этот оператор объявляет имя GROUP как тип структуры с тремя членами. Поскольку также указан тег
структуры, club , в объявлениях можно использовать как имя typedef ( GROUP ), так и тег структуры. С
тегом необходимо использовать ключевое слово struct; с именем typedef использование ключевого слова
struct не допускается.

typedef GROUP *PG; /* Uses the previous typedef name


to declare a pointer */

Тип PG объявлен как указатель на тип GROUP , который, в свою очередь, определен как тип структуры.

typedef void DRAWF( int, int );

В этом примере задан тип DRAWF для функции, не возвращающей никакого значения и принимающей два
аргумента int. Это означает , например, что объявление

DRAWF box;

эквивалентно объявлению

void box( int, int );

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

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

Более актуальные сведения по этой теме вы найдете в описании __declspec в справочнике по языку C++.

Расширенный синтаксис атрибутов упрощает и стандартизирует расширения для систем Microsoft в


соответствии с правилами языка C. К атрибутам класса хранения, в которых используется расширенный
синтаксис атрибутов, относятся: thread, naked, dllimport и dllexport.

Расширенный синтаксис атрибутов для указания информации о классе памяти использует ключевое слово
, которое указывает , что экземпляр заданного типа должен храниться с соответствующим атрибутом
класса хранения для систем Microsoft (thread, naked, dllimport или dllexport). Имеются и другие
модификаторы класса хранения: ключевые слова static и extern. Однако эти ключевые слова входят в
стандарт ANSI C, и как таковые они не используются с расширенным синтаксисом атрибутов.

Синтаксис
storage-class-specifier:
__declspec ( extended-decl-modifier-seq ) /* поддерживается только компилятором Майкрософт */
extended-decl-modifier-seq: /* Только для систем Майкрософт */
extended-decl-modifieropt
extended-decl-modifier-seq extended-decl-modifier
extended-decl-modifier: /* Только для систем Майкрософт */
thread
naked
dllimport
dllexport

Модификаторы объявления разделяются пробелами. Обратите внимание, что extended-decl-modifier-seq


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

Атрибуты класса хранения thread, naked, dllimport и dllexport являются свойством только объявления
данных или функции, к которому они применяются; они не переопределяют атрибуты типа самой
функции. Атрибут thread влияет только на данные. Атрибут naked влияет только на функции. Атрибуты
dllimport и dllexport влияют на функции и данные.
Завершение блока , относящегося только к системам Майкрософт

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

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

Модификаторы класса хранения dllimport и dllexport — это расширения языка С , характерные для систем
Microsoft. Эти модификаторы определяют интерфейс DLL клиента (исполняемый файл или другая
библиотека DLL). Дополнительные сведения об использовании этих модификаторов см. в статье dllexport,
dllimport.
Завершение блока , относящегося только к системам Майкрософт

См. также
Расширенные атрибуты классов хранения в C
Naked (C)
07.05.2020 • 2 minutes to read • Edit Online

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

Атрибут класса хранения naked является расширением языка C для систем Microsoft. Код функций,
объявленных с этим атрибутом, создается компилятором без кода пролога и эпилога. Благодаря этому вы
можете вставить в качестве пролога и эпилога свой собственный код на языке ассемблера. Функции с
атрибутом naked полезны для написания драйверов виртуальных устройств.

Дополнительные сведения см. в статье Функции Naked.

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

См. также
Расширенные атрибуты классов хранения в C
локальное хранилище потока
07.05.2020 • 4 minutes to read • Edit Online

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

Локальное хранилище потока (TLS) — это механизм, с помощью которого в каждом потоке многопоточного
процесса выделяется хранилище для хранения данных определенного потока. В стандартных
многопоточных программах данные совместно используются всеми потоками заданного процесса, в то
время как локальное хранилище потоков является механизмом предоставления данных для конкретного
потока. Полное описание потоков см. в статье Процессы и потоки в Windows SDK.

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

__declspec( thread ) int tls_i = 1;

При объявлении статистически связанных локальных переменных потока необходимо соблюдать


следующие рекомендации.

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


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

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

#define Thread __declspec( thread )


Thread void func(); /* Error */

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

#define Thread __declspec( thread )


void func1()
{
Thread int tls_i; /* Error */
}

int func2( Thread int tls_i ) /* Error */


{
return tls_i;
}

Атрибут потока следует использовать для объявления и определения локальных данных потока
независимо от того, выполняются ли объявление и определение в одном файле или в отдельных
файлах. Например, следующий код вызывает ошибку:
#define Thread __declspec( thread )
extern int tls_i; /* This generates an error, because the */
int Thread tls_i; /* declaration and the definition differ. */

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

char *ch __declspec( thread ); /* Error */

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

#define Thread __declspec( thread )


Thread int tls_i;
int *p = &tls_i; /* Error */

В языке C разрешена инициализация переменной с помощью выражения со ссылкой на себя, но


только для объектов нестатической области памяти. Пример:

#define Thread __declspec( thread )


Thread int tls_i = tls_i; /* Error */
int j = j; /* Error */
Thread int tls_i = sizeof( tls_i ) /* Okay */

Обратите внимание, что выражение sizeof, включающее инициализируемую переменную, не является


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

Использование __declspec(thread) может повлиять на отложенную загрузку импортов DLL.

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

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

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

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

Выражения L-Value и R-Value

Константные выражения

Побочные эффекты

Точки последовательности

Инструкции

Приоритет операторов

Преобразования типов

Приведение типов

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

Операнд — это сущность, с которой оператор выполняет какие-либо действия. Выражение — это
последовательность операторов и операндов, выполняющая действия ниже в любой комбинации.

Вычисление значения

Назначение объекта или функции

Создание побочных эффектов

Операнды в C включают константы, идентификаторы, строки, вызовы функций, выражения индекса,


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

См. также
Выражения и присваивания
Первичные выражения в C
15.05.2020 • 2 minutes to read • Edit Online

Операнды в выражениях называются основными выражениями.

Синтаксис
primary-expression:
identifier
constant
string-literal
( expression )
expression:
assignment-expression
expression , assignment-expression

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

Идентификаторы могут иметь целочисленный тип, тип, float , enum , struct , union , тип массива, тип
указателя или тип функции. Идентификатор представляет собой основное выражение, его он был объявлен
как обозначение объекта (тогда это l-значение) или как функция (тогда это обозначение функции).
Определение левостороннего значения приводится в статье Выражения L-Value и R-Value.

Значение указателя, представленное идентификатором массива, не является переменной, поэтому


идентификатор массива не может быть левым операндом операции присваивания и, следовательно, не
является изменяемым l-значением.

Идентификатор, объявленный как функция, представляет собой указатель, значением которого является
адрес функции. Указатель адресует функцию, возвращающую значение указанного типа. Таким образом,
идентификаторы функций также не могут быть l-значениями в операциях присваивания. Дополнительные
сведения см. в статье Идентификаторы.

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

Константный операнд имеет значение и тип того константного значения, которое он представляет.
Символьная константа имеет тип int . Целочисленная константа имеет тип int , long , unsigned int или
unsigned long (в зависимости от размера целого числа и от способа указания значения). Дополнительные
сведения см. в статье Константы.

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

"Строковый литерал" — это символ, расширенный символ или последовательность соседних символов,
заключенных в двойные кавычки. Поскольку эти символы не являются переменными, ни строковые
литералы, ни любой из их элементов не могут использоваться в качестве левого операнда в операции
присваивания. Тип строкового литерала — это массив char (или массив wchar_t для двухбайтовых
строковых литералов). Массивы в выражениях преобразуются в указатели. Дополнительные сведения о
строках см. в статье Строковые литералы.

См. также
Первичные выражения в C
Выражения в скобках
07.05.2020 • 2 minutes to read • Edit Online

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

( 10 + 5 ) / 5

скобки вокруг 10 + 5 означают , что значение 10 + 5 вычисляется первым и становится левым операндом
для оператора деления ( / ). Результат выражения ( 10 + 5 ) / 5 — 3. Без скобок результатом выражения
10 + 5 / 5 было бы значение 11.

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

( i++ +1 ) * ( 2 + i )

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

( 0 + 1 + 1 ) * ( 2 + 1 )
( 0 + 1 + 1 ) * ( 2 + 0 )

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

См. также
Первичные выражения в C
Выражения L-Value и R-Value
13.10.2020 • 3 minutes to read • Edit Online

Выражения, которые ссылаются на адреса памяти, называются выражениями l-значения. L-значение


представляет значение locator или left области хранения, что означает , что оно может отображаться
слева от знака равенства ( = ). L-значения часто являются идентификаторами.

Выражения, ссылающиеся на изменяемые расположения, называются изменяемыми l-значениями.


Изменяемое l-значение не может содержать тип массива, неполный тип или тип с атрибутом const .
Чтобы структуры и объединения были изменяемыми l-значениями, они не должны содержать элементы с
атрибутом const . Имя идентификатора обозначает место хранения, а значение переменной является
значением, хранящимся в этом месте.

Идентификатор является изменяемым l-значением, если он ссылается на адрес памяти и если он


принадлежит арифметическому типу, типу структуры, объединения или указателя. Например, если ptr
— указатель на область хранения, то *ptr будет изменяемым l-значением, которое обозначает область
хранения, на которую указывает ptr .

Любое из следующих выражений C может быть выражением l-значения.

Идентификатор целочисленного типа, типа указателя, структуры или объединения.

Выражение нижнего индекса ( [ ] ), результатом которого не является массив.

Выражение выбора члена ( -> или . )

Унарное косвенное выражение (* ), которое не ссылается на массив.

Выражение l-значения в скобках.

Объект const (неизменяемое l-значение).


Термин "r-значение" иногда используется, чтобы описать значение выражения и отличить его от l-
значения. Все l-значения являются r-значениями, но не все r-значения являются l-значениями.

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

Microsoft C включает расширение стандарта ANSI C, позволяющее использовать приведения l-значений


как l-значения, если размер объекта не увеличивается при приведении. Дополнительные сведения см. в
статье Type-Cast Conversions (Преобразования с приведением типов). Данная возможность показана в
следующем примере.

char *p ;
short i;
long l;

(long *) p = &l ; /* Legal cast */


(long) i = l ; /* Illegal cast */

В Microsoft C расширения Microsoft по умолчанию включены. Используйте параметр компилятора /Za для
отключения этих расширений.

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


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

Константное выражение вычисляется во время компиляции, а не во время выполнения, и может


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

Синтаксис
constant-expression:
conditional-expression
conditional-expression:
logical-OR-expression
logical-OR-expression ? expression : conditional-expression
expression:
assignment-expression
expression , assignment-expression
assignment-expression:
conditional-expression
unary-expression assignment-operator assignment-expression
assignment-operator: один из следующих операторов:
= *= /= %= += -= <<= >>= &= ^= |=
Нетерминальные слова для декларатора структуры, перечислителя, прямого декларатора, прямого
абстрактного декларатора и оператора с меткой содержат нетерминальное константное выражение.

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

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


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

См. также
Операнды и выражения
Вычисление выражений (C)
07.05.2020 • 2 minutes to read • Edit Online

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

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

См. также
Операнды и выражения
Побочные эффекты
07.05.2020 • 2 minutes to read • Edit Online

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


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

add( i + 1, i = j + 2 );
myproc( getc(), getc() );

Аргументы вызова функции могут вычисляться в любом порядке. Выражение i + 1 может вычисляться до
выражения i = j + 2 или выражение i = j + 2 может вычисляться до выражения i + 1 . В каждом
случае результат будет различным. Аналогично, невозможно гарантировать, какие символы фактически
будут переданы в myproc . Поскольку унарные операции инкремента и декремента связаны с
присваиваниями, такие операции могут вызывать побочные эффекты, как показано в следующем примере:

x[i] = i++;

В этом примере значение изменяемой переменной x непредсказуемо. Значение индекса может быть как
новым, так и старым значением переменной i . Результат может отличаться в различных компиляторах
или при разных уровнях оптимизации.

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

См. также
Вычисление выражений
Точки следования C
13.10.2020 • 3 minutes to read • Edit Online

Между последовательными «точками последовательности» значение объекта может быть изменено


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

Левый операнд оператора логического И ( && ). Перед продолжением левый операнд оператора
логического AND полностью вычисляется и учитываются все побочные эффекты. Если левый
операнд имеет значение False (0), значение второго операнда не вычисляется.

Левый операнд оператора логического OR ( || ). Перед продолжением левый операнд оператора


логического OR полностью вычисляется и учитываются все побочные эффекты. Если левый
операнд имеет значение True (не равен нулю), значение второго операнда не вычисляется.

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

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

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

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

Выражение в операторе выражения. Операторы-выражения состоят из необязательного выражения


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

Управляющее выражение в операторе выбора ( if или switch ). Перед выполнением кода,


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

Управляющее выражение оператора while или do . Перед выполнением любых операторов в


следующей итерации цикла while или do это выражение полностью вычисляется и вступают в
силу все побочные эффекты.

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

Выражение в операторе return . Перед возвратом управления в вызывающую функцию это


выражение полностью вычисляется и учитываются все побочные эффекты.

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

Операторы C являются подмножеством встроенных операторов C++.

Существуют три типа операторов. Унарное выражение состоит либо из унарного оператора, который
стоит перед операндом, либо из ключевого слова sizeof , за которым следует выражение. Выражением
может быть либо имя переменной, либо выражение приведения типа. В последнем случае выражение
должно быть заключено в круглые скобки. Бинарное выражение состоит из 2 операндов, соединенных
бинарным оператором. Троичное выражение состоит из 3 операндов, соединенных оператором условного
выражения.

В языке C имеются следующие унарные операторы:

СИМВОЛ NAME

-~! Операторы отрицания и дополнения

*& Операторы косвенного обращения и взятия адреса

sizeof Оператор определения размера

+ Оператор унарного сложения

++ -- Унарные операторы инкремента и декремента

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

СИМВОЛ NAME

*/% Мультипликативные операторы

+- Аддитивные операторы

<< >> Операторы сдвига

< > <= >= == != Операторы отношения

&|^ Побитовые операторы

&& || Логические операторы

, Оператор последовательного вычисления

Базовый оператор ( :> ), поддерживающийся предыдущими версиями компилятора Microsoft C для 16-
разрядных систем, описывается в кратком обзоре синтаксиса языка C.

Оператор условного выражения имеет более низкий приоритет , чем бинарные выражения, и отличается
от них тем, что имеет правую ассоциативность.
К выражениям с операторами также относятся выражения присваивания, в которых используются
унарные или бинарные операторы присваивания. Унарные операторы присваивания — это операторы
инкремента и декремента ( ++ и -- соответственно). Бинарные операторы присваивания — это оператор
простого присваивания ( = ) и составные операторы присваивания. Все составные операторы
присваивания состоят из другого бинарного оператора и оператора простого присваивания.

См. также
Выражения и присваивания
Приоритет и порядок оценки
13.10.2020 • 8 minutes to read • Edit Online

Приоритет и ассоциативность операторов C влияют на группировку и вычисление операндов в


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

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


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

Приоритет и ассоциативность операторов C


СИМВОЛ 1 ТИП ОПЕРАЦИИ АССОЦИАТИВНОСТЬ

[ ] ( ) . -> Выражение Слева направо


++ -- (постфикс)

sizeof & * + - ~ ! Унарный Справа налево


++ -- (префикс)

typecasts Унарный Справа налево

* / % Мультипликативный Слева направо

+ - Аддитивный Слева направо

<< >> Побитовый сдвиг Слева направо

< > <= >= Реляционный Слева направо

== != Равенство Слева направо

& Побитовое И Слева направо

^ Побитовое исключающее ИЛИ Слева направо

| Побитовое включающее ИЛИ Слева направо

&& Логическое И Слева направо

|| Логическое ИЛИ Слева направо

? : Условное выражение Справа налево


СИМВОЛ ТИП ОПЕРАЦИИ АССОЦИАТИВНОСТЬ

= *= /= %= Простое и составное присваивание 2 Справа налево


+= -= <<= >>= &=
^= |=

, Последовательное вычисление Слева направо

1 Операторы перечислены в порядке убывания приоритета. Если в одной строке или группе находится

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


2 Все операторы простого и составного присваивания имеют равный приоритет.

Выражение может содержать несколько операторов с равным приоритетом. Если несколько таких
операторов находятся в выражении на одном уровне, вычисление выполняется согласно их
ассоциативности (либо справа налево, либо слева направо). Направление вычисления не влияет на
результаты выражений, в которых на одном и том же уровне находится более одного оператора
умножения ( * ) или сложения ( + ) либо бинарного побитового оператора ( & , | или ^ ). Порядок
операций не определен языком. Если компилятор может гарантировать согласованный результат , то он
может вычислять такие выражения в любом порядке.

Только операторы последовательного вычисления ( , ), логический оператор AND ( && ), логический


оператор OR ( || ), операторы условных выражений ( ? : ) и операторы вызова функции создают точки
следования и тем самым гарантируют определенный порядок вычисления своих операндов. Оператор
вызова функции представляет собой пару скобок, следующих за идентификатором функции. Оператор
последовательного вычисления ( , ) гарантирует , что его операнды будут вычисляться слева направо
(оператор-запятая в вызове функции не является оператором последовательного вычисления и не
предоставляет таких гарантий). Дополнительные сведения см. в статье Точки следования C.

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

x && y++

второй операнд, y++ , вычисляется, только если x имеет значение true (не равно нулю). Таким образом,
если y дает значение false (0), то x не увеличивается.

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

ВЫРАЖЕНИЕ АВТОМАТИЧЕСКАЯ ПРИВЯЗКА

a & b || c (a & b) || c

a = b || c a = (b || c)

q && r || s-- (q && r) || s--

В первом выражении оператор побитового И ( & ) имеет более высокий приоритет , чем оператор
логического ИЛИ ( || ), поэтому a & b формирует первый операнд операции логического ИЛИ.

Во втором выражении оператор логического ИЛИ ( || ) имеет более высокий приоритет , чем оператор
простого присваивания ( = ), поэтому b || c группируется как правый операнд присваивания. Обратите
внимание, что операнду a присваивается значение 0 или 1.

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


непредвиденный результат. Оператор логического И ( && ) имеет более высокий приоритет , чем оператор
логического ИЛИ ( || ), поэтому q && r становится одним операндом. Так как логические операторы
гарантируют вычисление операндов слева направо, то операция q && r вычисляется раньше, чем s-- . Но
если выражение q && r имеет ненулевое значение, то s-- не вычисляется и s не уменьшается. Если то,
что значение s не будет уменьшено, может вызвать проблемы в вашей программе, вы можете либо
поставить s-- первым операндом в выражении, либо выполнить декремент s в отдельной операции.

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


компиляции.

НЕДОПУСТИМОЕ ВЫРАЖЕНИЕ ГРУППИРОВКА ПО УМОЛЧАНИЮ

p == 0 ? p += 1: p += 2 ( p == 0 ? p += 1 : p ) += 2

В этом выражении оператор равенства ( == ) имеет наибольший приоритет , поэтому выражение p == 0


становится одним операндом. Далее по приоритету следует оператор условного выражения ( ? : ). Его
первым операндом является p == 0 , а вторым — p += 1 . Однако последним операндом оператора
условного выражения считается не p , а p += 2 , поскольку в этом случае p имеет более тесную привязку
к оператору условного выражения, чем к оператору составного присваивания. Синтаксическая ошибка
возникает потому, что операция += 2 не имеет левого операнда. Для того чтобы избежать ошибок такого
рода и сделать код более читаемым, необходимо использовать скобки. Так, предыдущий пример можно
исправить при помощи круглых скобок, как показано ниже:

( p == 0 ) ? ( p += 1 ) : ( p += 2 )

См. также
Операторы в C
Обычные арифметические преобразования
13.10.2020 • 3 minutes to read • Edit Online

Большинство операторов C выполняют преобразования типов для приведения операндов выражения к


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

Арифметические преобразования, представленные ниже, называются обычными арифметическими


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

1. Если какой-либо из операндов имеет тип long double , то другой операнд преобразуется в тип
long double .

2. Если вышеуказанное условие не выполняется, а один из операндов имеет тип double , то второй
операнд преобразуется в тип double .

3. Если два вышеуказанных условия не выполняются, а один из операндов имеет тип float , то второй
операнд преобразуется в тип float .

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

Если какой-либо из операндов имеет тип unsigned long , то другой операнд преобразуется в
тип unsigned long .

Если вышеуказанное условие не выполняется, при этом один из операндов имеет тип long ,а
второй — тип unsigned int , то оба операнда преобразуются в тип unsigned long .

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

Если три вышеуказанных условия не выполняются и какой-либо из операндов имеет тип


unsigned int , то другой операнд преобразуется в тип unsigned int .

Если ни одно из вышеуказанных условий не соблюдается, то оба операнда преобразуются в


тип int .

Эти правила преобразования демонстрируются в следующем примере.


float fVal;
double dVal;
int iVal;
unsigned long ulVal;

dVal = iVal * ulVal; /* iVal converted to unsigned long


* Uses step 4.
* Result of multiplication converted to double
*/
dVal = ulVal + fVal; /* ulVal converted to float
* Uses step 3.
* Result of addition converted to double
*/

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

Постфиксные операторы имеют самый высокий приоритет (наиболее тесную привязки) в вычислении
выражений.

Синтаксис
postfix-expression:
primary-expression
postfix-expression [ expression ]
postfix-expression ( argument-expression-listopt )
postfix-expression . identifier
postfix-expression -> identifier
postfix-expression ++
postfix-expression --
Операторы на этом уровне приоритета являются индексами массива, функциональными вызовами,
структурными элементами и членами объединений, а также постфиксными операторами приращения и
уменьшения.

См. также
Операторы в C
Одномерные массивы
13.10.2020 • 3 minutes to read • Edit Online

Постфиксное выражение, за которым следует выражение в квадратных скобках ( [ ] ), является


представлением элемента объекта массива с индексом. Выражение с индексом в представленной ниже
форме ссылается на значение, размешенное по адресу на expression позиций дальше postfix-expression:

postfix-expression [ expression ]

Обычно postfix-expression является указателем, например идентификатором массива, а expression является


целочисленным значением. Однако все, что необходимо синтаксически, — это чтобы одно из выражений
имело тип указателя, а другие — целочисленный тип. Таким образом, целочисленное значение может
находиться в позиции postfix-expression, а значение указателя — в "позиции индекса", т. е. expression.
Например, такой код является допустимым:

// one_dimensional_arrays.c
int sum, *ptr, a[10];
int main() {
ptr = a;
sum = 4[ptr];
}

Выражения индекса обычно используются для ссылки на элементы массива, но индекс может применяться к
любому указателю. Независимо от порядка значений, выражение expression должно быть заключено в
квадратные скобки ( [ ] ).

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


результат передается в оператор косвенного обращения (* ). (Этот механизм обсуждается в статье
Операторы косвенного обращения и адреса операнда.) В конечном итоге в случае одномерного массива
следующие 4 выражения эквивалентны, при условии что a является указателем, а b — целым числом:

a[b]
*(a + b)
*(b + a)
b[a]

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

Например, предположим, что идентификатор line ссылается на массив значений int . Для вычисления
выражения индекса line[ i ] используется следующая процедура:

1. Целочисленное значение i умножается на количество байт , определенное как длина элемента int
. Преобразованное значение i представляет позиции i int .
2. Это преобразованное значение добавляется к исходному значению указателя ( line ) для получения
адреса, представляющего позиции, смещенные на i int относительно line .

3. Оператор косвенного обращения применяется к новому адресу. Результат представляет собой


значение элемента массива в этой позиции (интуитивно, line [ i ] ).
Выражение индекса line[0] представляет значение первого элемента массива line, поскольку смещение от
адреса, представляемого line , равно 0. Аналогично, выражение line[5] ссылается на элемент , смещенный
на 5 позиций относительно line, или на шестой элемент массива.

См. также
Оператор индекса:
Многомерные массивы (C)
13.10.2020 • 3 minutes to read • Edit Online

Индексное выражение также может иметь несколько индексов, как показано ниже:

expression1 [ expression2 ] [ expression3 ] ...

Индексные выражения связываются в направлении слева направо. Сначала вычисляется левое индексное
выражение expression1 [ expression2 ] . Адрес, получающийся в результате сложения expression1 и
expression2, формирует выражение указателя. Затем к этому выражению указателя добавляется выражение
expression3, чтобы образовать новое выражение указателя. Эти операции повторяются до тех пор, пока не
будет добавлено последнее индексное выражение. После вычисления последнего индексного выражения
выполняется оператор косвенного обращения (* ), если конечное значение указателя не указывает на тип
массива (см. примеры ниже).

Выражения с несколькими индексами ссылаются на элементы многомерных массивов. Многомерный


массив — это массив, элементы которого сами являются массивами. Например, первый элемент
трехмерного массива является двумерным массивом.

Примеры
В следующих примерах массив с именем prop объявляется с тремя элементами, каждый из которых
представляет собой массив 4x6, содержащий значения типа int .

int prop[3][4][6];
int i, *ip, (*ipp)[6];

Ссылка на массив prop выглядит следующим образом:

i = prop[0][0][1];

В приведенном выше примере показано, как ссылаться на второй отдельный элемент int массива prop .
Массивы хранятся по строкам, поэтому последний индекс изменяется быстрее; выражение prop[0][0][2]
ссылается на следующий (третий) элемент массива и т. д.

i = prop[2][1][3];

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

1. Первый индекс, 2 , умножается на размер массива int 4x6 и добавляется к значению указателя prop
. Результат указывает на третий массив 4x6 массива prop .
2. Второй индекс,
1 , умножается на размер 6-элементного массива int и добавляется к адресу,
представленному значением prop[2] .

3. Каждый элемент 6-элементного массива является значением типа int , поэтому конечный индекс,
3 , перед добавлением к выражению prop[2][1] умножается на размер int . Результирующий
указатель указывает на четвертый элемент 6-элементного массива.
4. Оператор косвенного обращения применяется к значению указателя. Результат — элемент int ,
расположенный по этому адресу.

Ниже приведены два примера, в которых оператор косвенного обращения не применяется.

ip = prop[2][1];

ipp = prop[2];

В первом из показанных операторов выражение prop[2][1] представляет собой допустимую ссылку на


трехмерный массив prop ; эта ссылка относится к 6-элементному массиву (объявленному выше). Поскольку
значение указателя указывает на массив, оператор косвенного обращения не применяется.

Аналогично результат выражения prop[2] во втором операторе ipp = prop[2]; представляет значение
указателя, указывающее на двумерный массив.

См. также
Оператор индекса:
Вызов функций (C)
13.10.2020 • 2 minutes to read • Edit Online

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

Синтаксис
postfix-expression:
postfix-expression ( argument-expression-listopt )
argument-expression-list:
assignment-expression
argument-expression-list , assignment-expression
Выражение postfix-expression должно вычислять адрес функции (например, идентификатор функции или
значение указателя функции), а argument-expression-list содержит список выражений (разделенных
запятыми), значения которых (аргументы) передаются функции. Аргумент argument-expression-list может
быть пустым.

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

См. также
Оператор вызова функции: ()
Члены структур и объединений
13.10.2020 • 2 minutes to read • Edit Online

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

postfix-expression . identifier
postfix-expression -> identifier

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

1. В первой форме postfix-expression представляет значение типа struct или union , а identifier
именует элемент указанной структуры или объединения. Значение операции совпадает с identifier и
является l-значением, если postfix-expression является l-значением. Дополнительные сведения см. в
разделе Выражения l-значений и r-значений.

2. Во второй форме postfix-expression представляет указатель на структуру или объединение, а


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

Две формы выражений выбора члена оказывают аналогичное влияние.

Фактически выражение, включающее оператор выбора члена ( -> ), — это сокращенная версия выражения,
использующего точку ( . ), если выражение перед точкой включает оператор косвенного обращения (* ),
примененный к значению указателя. Поэтому

expression->identifier

эквивалентно

(*expression).identifier

если expression — значение указателя.

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

struct pair
{
int a;
int b;
struct pair *sp;
} item, list[10];

Выражение выбора члена для структуры item выглядит следующим образом.


item.sp = &item;

В приведенном выше примере адрес структуры item присваивается члену sp структуры. Это означает ,
что item содержит указатель на себя.

(item.sp)->a = 24;

В этом примере выражение указателя item.sp используется с оператором выбора члена ( -> ) для
присвоения значения члену a .

list[8].b = 12;

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

См. также
Операторы для доступа к членам: . и ->
Постфиксные операторы увеличения и
уменьшения в C
15.05.2020 • 2 minutes to read • Edit Online

Операнды операторов постфиксных инкремента и декремента являются скалярными типами,


представляющими собой изменяемые L-значения.

Синтаксис
postfix-expression:
postfix-expression ++
postfix-expression --
Результатом операции постфиксного инкремента или декремента является значение операнда. После
получения результата значение операнда инкрементируется (или декрементируется). В следующем примере
кода демонстрируется оператор постфиксного инкремента.

if( var++ > 0 )


*p++ = *q++;

В этом примере переменная var сравнивается с нулем и затем инкрементируется. Если значение var до
инкрементирования было положительным, выполняется следующий оператор. Сначала значение объекта,
на который указывает q , присваивается объекту, на который указывает p . Затем q и p
инкрементируются.

См. также
Постфиксные операторы увеличения и уменьшения: ++ и --
Унарные операторы C
13.10.2020 • 2 minutes to read • Edit Online

Унарные операторы располагаются до операнда, и связь устанавливается справа налево.

Синтаксис
unary-expression: postfix-expression
++ unary-expression
-- unary-expression
unary-operator cast-expression
sizeof unary-expression
sizeof ( type-name )
unary-operator: один из операторов & * + - ~ !

См. также
Операторы в C
Префиксные операторы увеличения и уменьшения
13.10.2020 • 2 minutes to read • Edit Online

Унарные операторы ( ++ и -- ) называются операторами префиксного инкремента или декремента, если


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

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

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

Пример
В следующем примере показан унарный оператор префиксного декремента.

if( line[--i] != '\n' )


return;

В этом примере переменная i уменьшена до использования в качестве нижнего индекса line .

См. также
Унарные операторы C
Операторы косвенного обращения и адреса
операнда
13.10.2020 • 4 minutes to read • Edit Online

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


Операнд должен иметь тип указателя. Результатом операции является значение в том адресе, на который
указывает операнд. Тип результата совпадает с типом значения в адресе операнда.

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

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

Указатель является пустым указателем.

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

Указатель определяет адрес, который не используется выполняемой программой.

Унарный оператор взятия адреса ( & ) предоставляет адрес своего операнда. Операнд может быть либо
значением, адресующим объект , который не объявлен как register и не является битовым полем, либо
результатом унарного оператора * или оператора разыменования массива ( [] ), либо обозначением
функции. Результат является указателем на тип, если тип операнда — тип.

Если операнд является результатом унарного оператора * , ни один из операторов не вычисляется, как
если бы они оба были пропущены. Результат не является адресующим значением, и к операторам по-
прежнему применяются ограничения. Если операнд является результатом оператора [] , то ни оператор & ,
ни унарный оператор * , подразумеваемый оператором [] , не вычисляются. Результат будет таким же, как
при удалении оператора & и смене оператора [] на + . В противном случае будет получен указатель на
объект или функцию, назначаемую операндом.

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

int *pa, x;
int a[20];
double d;

Эта инструкция использует оператор взятия адреса ( & ) для получения адреса шестого элемента массива
a . Результат сохраняется в переменной указателя pa :

pa = &a[5];

Оператор косвенного обращения ( * ) в этом примере обращается к значению int по адресу,


сохраненному в переменной pa . Значение присваивается целочисленной переменной x :
x = *pa;

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

assert( x == *&x );

Этот пример показывает эквивалентные способы объявления указателя на функцию.

int roundup( void ); /* Function declaration */

int *proundup = roundup;


int *pround = &roundup;
assert( pround == proundup );

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

См. также
Оператор косвенного обращения: *
Оператор address-of: &
Унарные арифметические операторы
13.10.2020 • 2 minutes to read • Edit Online

Оператор унарного плюса C, арифметического отрицания, дополнения и логического отрицания


обсуждаются в следующем списке.

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

+ Оператор унарного плюса, предшествующий выражению


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

- Оператор арифметического отрицания создает


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

~ Оператор побитового дополнения (или bitwise-NOT)


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

! Оператор логического отрицания (logical-NOT) создает


значение 0, если операнд равен true (ненулевой), и
значение 1, если операнд равен false (0). Результат имеет
тип int . Этот операнд должен представлять собой
целочисленное значение, значение с плавающей запятой
или значение указателя.

Унарные арифметические операции с указателями недопустимы.

Примеры
В следующих примерах показаны унарные арифметические операторы:

short x = 987;
x = -x;

В приведенном выше примере новое значение x является отрицательной формой 987 или –987.

unsigned short y = 0xAAAA;


y = ~y;
В этом примере новое значение, присвоенное переменной y , является дополнением до единицы значения
0xAAAA или 0x5555 без знака.

if( !(x < y) )

Если x больше или равно y , результат выражения равен 1 (true). Если x меньше y , результат равен 0
(false).

См. также
Выражения с унарными операторами
Оператор sizeof (C)
13.10.2020 • 3 minutes to read • Edit Online

Оператор sizeof предоставляет объем хранения (в байтах), необходимого для хранения объекта типа
"операнд". Этот оператор позволяет избежать задания зависимых от компьютера размера данных в
программах.

Синтаксис
sizeof unary-expression
sizeof ( type-name )

Примечания
Операнд является либо любым идентификатором unary-expression, либо выражением type-cas (то есть
описателем типа, заключенным в скобки). unary-expression не может представлять объект битового поля,
неполный тип или указатель функции. Результатом является целочисленная константа без знака.
Стандартный заголовок STDDEF.H определяет этот тип как size_t .

При применении оператора sizeof к идентификатору массива результатом является размер целого
массива, а не размер указателя, представленного идентификатором массива.

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

Если безразмерный массив является последним элементом структуры, оператор sizeof возвращает размер
структуры без массива.

buffer = calloc(100, sizeof (int) );

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

static char *strings[] = {


"this is string one",
"this is string two",
"this is string three",
};
const int string_no = ( sizeof strings ) / ( sizeof strings[0] );

В этом примере strings — это массив указателей на char . Число указателей — это число элементов в
массиве, но оно не определено. Легко определить количество указателей с помощью оператора sizeof ,
вычислив число элементов в массиве. Значение целого числа const string_no инициализируется до этого
числа. Поскольку это значение const , string_no невозможно изменить.
См. также
Операторы в C
Операторы C++, приоритет и ассоциативность
Операторы приведения
15.05.2020 • 2 minutes to read • Edit Online

Приведение типа позволяет выполнить явное преобразование типа объекта в конкретной ситуации.

Синтаксис
cast-expression: unary-expression
( type-name ) cast-expression
После выполнения приведения типа компилятор считает , что cast-expression имеет тип type-name.
Приведение типов можно использовать для преобразования объектов любого скалярного типа в любой
другой скалярный тип и из любого другого скалярного типа. Явное приведение типов ограничено теми же
правилами, которые используются для неявных преобразований, как описано в статье Преобразования
назначений. Дополнительные ограничения на операции приведения могут быть связаны с фактическими
размерами или представлением конкретных типов. Сведения о фактических размерах целочисленных типов
см. в статье Хранение базовых типов. Дополнительные сведения о приведении типов см. в статье
Преобразования с приведением типов.

См. также
Оператор приведения типа: ()
Операторы умножения в C
13.10.2020 • 4 minutes to read • Edit Online

Мультипликативные операторы выполняют операции умножения (* ), деления ( / ) и вычисления остатка ( %


).

Синтаксис
multiplicative-expression: cast-expression multiplicative-expression * cast-expression multiplicative-
expression / cast-expression multiplicative-expression % cast-expression
Операнды оператора вычисления остатка ( % ) должны быть целочисленными. Операторы умножения (* ) и
деления ( / ) могут принимать операнды целочисленного типа и операнды с плавающей запятой, при этом
допускаются операнды разных типов.

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


После преобразования тип результата совпадает с типом операндов.

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

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

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

* Оператор умножения выполняет умножение двух


операндов.

/ Оператор деления выполняет деление первого операнда


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

— Согласно стандарту ANSI C результат деления на 0 не


определен. Во время компиляции или выполнения
компилятор Microsoft C выдает ошибку.

— Если оба операнда положительные или не имеют


знака, дробная часть результата отбрасывается.

— Если один из операндов отрицательный, результатом


операции может быть наибольшее целое число, меньшее
или равное частному от деления, или наименьшее целое
число, большее или равное частному от деления. Это
определяется реализацией. (См. раздел "Для систем
Майкрософт " ниже.)
ОПЕРАТОР ОПИСАНИЕ

% Результат выполнения оператора вычисления остатка —


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

— Если правый операнд равен нулю, результат будет


неопределенным.

— Если оба операнда положительные или не имеют


знака, результат будет положительным.

— Если один из операндов отрицательный и результат


неточный, результат определяется реализацией. (См.
раздел "Для систем Майкрософт " ниже.)

Специально для систем Майкрософт


Если при делении один из операндов отрицательный, дробная часть результата отбрасывается.

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

Примеры
Для приведенных ниже примеров используются следующие объявления:

int i = 10, j = 3, n;
double x = 2.0, y;

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

y = x * i;

В этом примере x умножается на i и получается значение 20.0. Результат имеет тип double .

n = i / j;

В этом примере 10 делится на 3. Дробная часть результата отбрасывается и получается целое значение 3.

n = i % j;

В этой инструкции переменной n присваивается значение целочисленного остатка (1) от деления 10 на 3.

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

Знак остатка совпадает со знаком делимого. Пример:

50 % -6 = 2
-50 % 6 = -2

В каждом случае значения 50 и 2 имеют один и тот же знак.

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


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

Аддитивные операторы выполняют сложение ( + ) и вычитание ( - ).

Синтаксис
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression

NOTE
Хотя синтаксис выражения-сложения включает выражение-умножения, это не означает , что требуются
выражения, в которых используется умножение. Синтаксис выражения-умножения, выражения-приведения и
унарного выражения см. в документе Краткие сведения о синтаксисе языка C.

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

Аддитивные операторы выполняют обычные арифметические преобразования с операндами


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

См. также
Аддитивные операторы: + и -
Сложение (+)
07.05.2020 • 2 minutes to read • Edit Online

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

Если целое число добавить к указателю, целое значение целого числа (i) будет преобразовано с помощью
его умножения на размер значения, к которому обращается указатель. После преобразования значение
целого числа представляет позиции памяти i, где каждая позиция имеет длину, заданную типом указателя.
Если преобразованное значение целого числа добавить ко значению указателя, будет получено новое
значение указателя, представляющее позиции i адреса из исходного адреса. Новое значение указателя
обращается ко значению того же типа, что и исходное значение указателя. Следовательно, эта операция
аналогична индексации массива (см. статьи Одномерные массивы и Многомерные массивы (C)). Если
указатель суммы указывает за пределы массива, за исключением первого расположения, находящегося за
верхним пределом, результат не определен. Дополнительные сведения см. в статье Расчеты с указателями.

См. также
Аддитивные операторы в C
Вычитание (-)
07.05.2020 • 2 minutes to read • Edit Online

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

При вычитании двух указателей разница преобразуется в целочисленное значение со знаком путем деления
разницы на размер значения типа, к которому обращаются указатели. Размер целочисленного значения
определяется типом ptrdiff_t в стандартном включаемом файле STDDEF.H. Результат представляет собой
число позиций памяти данного типа, расположенных между двумя адресами. Результат гарантировано
имеет значение только для двух элементов одного массива, как описано в разделе Арифметические
операции с указателями.

Если целочисленное значение вычитается из значения указателя, оператор вычитания преобразует


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

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

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


объявления.

int i = 4, j;
float x[10];
float *px;

Эти операторы эквивалентны.

px = &x[4 + i];
px = &x[4] + i;

Значение i умножается на длину типа float и добавляется к &x[4] . Результирующее значение указателя
является адресом x[8] .

j = &x[i] - &x[i-2];

В этом примере адрес третьего элемента x (заданного x[i-2] ) вычитается из адреса пятого элемента x
(заданного x[i] ). Разница делится на длину типа float ; результатом является целочисленное значение 2.

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

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

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

Аналогично, когда производится вычитание значений двух указателей, при преобразовании


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

См. также
Аддитивные операторы в C
Операторы побитового сдвига
13.10.2020 • 3 minutes to read • Edit Online

Операторы сдвига сдвигают свой первый операнд влево ( << ) или вправо ( >> ) на число позиций,
задаваемое вторым операндом.

Синтаксис
shift-expression:
additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression
Оба операнда должны быть целыми значениями. Эти операторы выполняют обычные арифметические
преобразования; типом результата является тип левого операнда после преобразования.

В случае сдвига влево для освобождаемых правых битов задается значение 0. В случае сдвига вправо
освобождающиеся левые биты заполняются в зависимости от типа первого операнда после
преобразования. В случае типа unsigned для них устанавливается значение 0. В противном случае они
заполняются путем копирования бита знака. Для операторов сдвига влево без переполнения оператор

expr1 << expr2

эквивалентен умножению на 2expr2. Для операторов сдвига вправо операция

expr1 >> expr2

эквивалентна делению на 2expr2, если операнд expr1 не имеет знака или имеет неотрицательное значение.

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

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


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

unsigned int x, y, z;

x = 0x00AA;
y = 0x5500;

z = ( x << 8 ) + ( y >> 8 );

В этом примере значение x сдвигается влево на 8 позиций, а значение y сдвигается вправо на 8 позиций.
Значения после сдвига складываются, а получившееся в результате число 0xAA55 присваивается
переменной z .

Сдвиг вправо отрицательного значения соответствует делению исходного значения на два с округлением
вниз. Например, сдвиг вправо значения –253 (11111111 00000011 в двоичном представлении) дает
значение –127 (11111111 10000001 в двоичном представлении). Сдвиг вправо положительного числа 253
дает +126.
При сдвиге вправо бит знака сохраняется. При сдвиге вправо целого числа со знаком старший значащий бит
остается установленным. При сдвиге вправо целого числа без знака старший значащий бит очищается.

См. также
Операторы сдвигов влево и вправо (>> и <<)
Операторы отношения и равенства C
13.10.2020 • 5 minutes to read • Edit Online

Операторы отношения и равенства сравнивают свои первые и вторые операнды для проверки истинности
указанного отношения. Результат выражения отношения равен 1, если проверенное отношение истинно,
или 0, если отношение ложно. Результат имеет тип int .

Синтаксис

relational-expression:
shift-expression
relational-expression < shift-expression
relational-expression > shift-expression
relational-expression <= shift-expression
relational-expression >= shift-expression
equality-expression:
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression
Операторы отношения и равенства проверяют следующие отношения.

ОПЕРАТОР ПРОВЕРЯЕМОЕ ОТНОШЕНИЕ

< Первый операнд меньше второго операнда

> Первый операнд больше второго операнда

<= Первый операнд меньше или равен второму операнду

>= Первый операнд больше или равен второму операнду

== Первый операнд равен второму операнду

!= Первый операнд не равен второму операнду

Первые четыре оператора в приведенном выше списке имеют более высокий приоритет , чем операторы
равенства ( == и != ). Сведения о приоритетах приведены в таблице Приоритет и ассоциативность
операторов C.

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

Оба операнда любого оператора отношения или равенства могут быть указателями на один и тот же
тип. Для операторов равенства ( == ) и неравенства ( != ) результат сравнения показывает , указывают
ли оба указателя на один и тот же адрес в памяти. Для других операторов отношения ( < , > , < =, and
> =), результат сравнения указывает относительное положение двух адресов памяти для объектов, на
которые указывают указатели. Операторы отношения сравнивают только смещения.
Сравнение указателей определено только для частей одного и того же объекта. Если указатели
относятся к элементам массива, сравнение аналогично сравнению соответствующих индексов. Адрес
первого элемента массива "меньше" адреса последнего элемента. В случае структур указатели на те
члены структуры, которые были объявлены позже, "больше" указателей на члены, объявленные в
структуре ранее. Указатели на члены одного объединения эквивалентны.

Значение указателя можно сравнивать с постоянным значением 0 на равенство ( == ) или неравенство


( != ). Указатель со значением 0 называется указателем "null"; иными словами, он не указывает на
допустимое расположение в памяти.

В операторах равенства используются те же правила, что и для операторов отношения, но


допускаются дополнительные возможности: указатель можно сравнить с постоянным целочисленным
выражением, имеющим значение 0, или с указателем на void . Два указателя "null" при сравнении
считаются равными. Операторы равенства сравнивают как сегмент , так и смещение.

Примеры
Ниже показаны примеры операторов отношения и равенства.

int x = 0, y = 0;
if ( x < y )

Поскольку x и y равны, выражение в этом примере возвращает значение 0.

char array[10];
char *p;

for ( p = array; p < &array[10]; p++ )


*p = '\0';

Фрагмент в этом примере задает для каждого элемента массива array постоянное символьное значение
null.

enum color { red, white, green } col;


.
.
.
if ( col == red )
.
.
.

Эти операторы объявляют переменную перечисления с именем col и тегом color . В любой момент
времени эта переменная может содержать целочисленное значение 0, 1 или 2, которое представляет один
из элементов перечисления color : красный, белый или зеленый цвет , соответственно. Если переменная
col содержит значение 0 при выполнении оператора if , будут выполнены все операторы, зависящие от
этого оператора if .

См. также
Операторы отношения: <, >, <=, and >=
Операторы равенства: == и !=
Побитовые операторы в C
15.05.2020 • 3 minutes to read • Edit Online

Побитовые операторы выполняют операции побитового И ( & ), побитового исключающего ИЛИ ( ^ ) и


побитового включающего ИЛИ ( | ).

Синтаксис
AND-expression: equality-expression AND-expression & equality-expression
exclusive-OR-expression: AND-expression exclusive-OR-expression ^ AND-expression
inclusive-OR-expression: exclusive-OR-expression inclusive-OR-expression | exclusive-OR-expression
Операнды побитовых операторов должны иметь целочисленные типы, но их типы могут отличаться. Эти
операторы выполняют обычные арифметические преобразования; типом результата является тип операнда
после преобразования.

Ниже описываются побитовые операторы C.

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

& Оператор побитового И сравнивает каждый бит первого


операнда с соответствующим битом второго операнда.
Если оба бита равны 1, соответствующий бит результата
устанавливается равным единице. в противном случае —
нулю.

^ Оператор побитового исключающего ИЛИ сравнивает


каждый бит первого операнда с соответствующим битом
второго операнда. Если один бит равен 0, а другой равен
1, соответствующий бит результата устанавливается
равным 1. в противном случае — нулю.

| Оператор побитового включающего ИЛИ сравнивает


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

Примеры
Эти объявления используются для следующих трех примеров:

short i = 0xAB00;
short j = 0xABCD;
short n;

n = i & j;

Результат , присваиваемый переменной n в первом примере, совпадает с результатом i


(шестнадцатеричное значение 0xAB00).
n = i | j;

n = i ^ j;

Побитовое включающее ИЛИ во втором примере имеет своим результатом шестнадцатеричное значение
0xABCD, в то время как побитовое исключающее ИЛИ в третьем примере — шестнадцатеричное значение
0xCD.
Блок , относящийся только к системам Microsoft

Результаты побитовых операций со знаковыми целочисленными значениями зависят от реализации,


согласно стандарту ANSI C. Для компилятора Microsoft C побитовые операции со знаковыми
целочисленными значениями работают так же, как побитовые операции с беззнаковыми целочисленными
значениями. Например, значение -16 & 99 можно представить в двоичном виде следующим образом:

11111111 11110000
& 00000000 01100011
_________________
00000000 01100000

Выполнение побитовой операции И даст десятичное значение 96.

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

См. также
Оператор побитового И: &
Оператор побитового исключающего ИЛИ: ^
Оператор побитового включающего ИЛИ: |
Логические операторы в C
13.10.2020 • 3 minutes to read • Edit Online

Логические операторы выполняют операции логического И ( && ) и логического ИЛИ ( || ).

Синтаксис
logical-AND-expression:
inclusive-OR-expression
logical-AND-expression && inclusive-OR-expression
logical-OR-expression:
logical-AND-expression
logical-OR-expression || logical-AND-expression

Примечания
Логические операторы не выполняют обычных арифметических преобразований. Вместо этого они
оценивают каждый операнд с точки зрения его эквивалентности нулю. Результатом логической операции
является либо 0, либо 1. Результат имеет тип int .

Логические операторы C описываются ниже.

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

&& Логический оператор И создает значение 1, если оба


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

|| Оператор логического ИЛИ выполняет над своими


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

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

Примеры
В следующем примере показано использование логических операторов.

int w, x, y, z;

if ( x < y && y < z )


printf( "x is less than z\n" );
В этом примере функция printf вызывается для вывода сообщения, если x меньше y , а y меньше z . Если
x больше y , то второй операнд ( y < z ) не вычисляется и сообщение не печатается. Обратите внимание,
что это может привести к возникновению проблем в случаях, когда второй операнд имеет побочные
эффекты, на которые по ряду причин может рассчитывать программист.

printf( "%d" , (x == w || x == y || x == z) );

В этом примере, если x равно w , y или z , то второй аргумент функции printf имеет значение true и код
выводит значение 1. В противном случае он возвращает значение false и код выводит значение 0. Как
только обнаруживается, что одно из значений равно true, вычисление прекращается.

См. также
Оператор логического И: &&
Оператор логического ИЛИ: ||
Оператор Conditional-Expression
13.10.2020 • 3 minutes to read • Edit Online

В языке C есть один тернарный оператор: оператор условного выражения ( ? : ).

Синтаксис
conditional-expression:
logical-OR-expression
logical-OR expression ? expression : conditional-expression
Выражение logical-OR-expression может иметь целочисленный тип, тип с плавающей запятой или тип
указателя. Оно вычисляется с точки зрения эквивалентности значению 0. Точка последовательности
следует за выражением logical-OR-expression. Вычисление операндов продолжается следующим образом.

Если logical-OR-expression не равно 0, вычисляется выражение expression. Результат вычисления


общего выражения определяется нетерминальным выражением expression. (Это означает , что
expression вычисляется только в том случае, когда logical-OR-expression имеет значение true.)
Если logical-OR-expression равно 0, вычисляется выражение conditional-expression. Тогда результатом
общего выражения является значение conditional-expression. (Это означает , что conditional-expression
вычисляется только в том случае, когда logical-OR-expression имеет значение false.)

Обратите внимание, что из выражений expression и conditional-expression вычисляется только одно.

Тип результата условной операции зависит от типа операнда expression или conditional-expression, как
показано ниже.

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

Если expression и conditional-expression имеют одинаковый тип структуры, объединения или


указателя, результат получит такой же тип структуры, объединения или указателя.

Если оба операнда имеют тип void , результат будет принадлежать типу void .
Если какой-либо из операндов является указателем на объект любого типа, а второй операнд
является указателем на void , указатель на объект преобразуется в указатель на void , и
результатом является указатель на void .

Если одно из выражений expression или conditional-expression является указателем, а другое —


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

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

Примеры
В следующих примерах показаны варианты использования условного оператора.
j = ( i < 0 ) ? ( -i ) : ( i );

В этом примере абсолютное значение i присваивается j . Если значение i меньше 0, значение -i


присваивается j . Если значение i больше или равно 0, значение i присваивается j .

void f1( void );


void f2( void );
int x;
int y;
.
.
.
( x == y ) ? ( f1() ) : ( f2() );

В этом примере объявляется две функции f1 и f2 и две переменные x и y . Далее в программе, если две
переменные имеют одинаковое значение, вызывается функция f1 . В противном случае вызывается функция
f2 .

См. также
Условный оператор: ? :
Операторы назначения в C
15.05.2020 • 2 minutes to read • Edit Online

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

Синтаксис
assignment-expression:
conditional-expression
unary-expression assignment-operator assignment-expression
assignment-operator: один из следующих операторов:
= *= /= %= += -= <<= >>= &= ^= |=
Операторы присваивания в языке C позволяют в ходе одной операции выполнить и преобразование, и
присваивание значения. В языке C имеются следующие операторы присваивания:

ОПЕРАТОР ВЫПОЛНЯЕМАЯ ОПЕРАЦИЯ

= Простое присваивание

*= Присваивание умножения

/= Присваивание деления

%= Присваивание остатка

+= Присваивание сложения

-= Присваивание вычитания

<<= Присваивание сдвига влево

>>= Присваивание сдвига вправо

&= Присваивание побитового И

^= Присваивание побитового исключающего ИЛИ

|= Присваивание побитового включающего ИЛИ

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

См. также
Операторы присваивания
Простое назначение (C)
13.10.2020 • 2 minutes to read • Edit Online

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

double x;
int y;

x = y;

В этом примере значение переменной y преобразуется в тип double и присваивается переменной x .

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

Составные операторы присваивания объединяют оператор простого присваивания с другим бинарным


оператором. Составные операторы присваивания выполняют операцию, заданную дополнительными
оператором, затем присваивают результат левому операнду. Например, составное выражение присваивания

expression1 += expression2

можно понимать как

expression1 = expression1 + expression2

Но составной оператор присваивания не эквивалентен своей развернутой версии, так как в составном
операторе присваивания выражение выражение1 вычисляется только один раз, а в развернутой версии
выражение выражение1 вычисляется дважды: в операции сложения и в операции присваивания.

Операнды составного оператора присваивания должны быть целочисленного типа или типа с плавающей
запятой. Каждый составной оператор присваивания выполняет те же преобразования, что и
соответствующий бинарный оператор, и соответственно ограничивает типы своих операндов. Левый
операнд операторов сложения с присваиванием ( += ) и вычитания с присваиванием ( -= ) может иметь тип
указателя, при этом правый операнд должен быть целочисленного типа. Результат составной операции
присваивания имеет значение и тип левого операнда.

#define MASK 0xff00

n &= MASK;

В этом примере операция побитового включающего AND выполняется для n и MASK , а результат
присваивается переменной n . Константа манифеста MASK определяется с помощью директивы
препроцессора #define.

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

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

Синтаксис
expression:
assignment-expression
expression , assignment-expression
Левый операнд оператора последовательного вычисления вычисляется как выражение void . Результат
операции имеет те же значение и тип, что и правый операнд. Каждый операнд может быть любого типа.
Оператор последовательного вычисления не выполняет преобразования типов своих операндов и не
создает L-значение. После первого операнда находится точка следования. Это означает , что до вычисления
правого операнда учитываются все побочные эффекты вычисления левого операнда. Дополнительные
сведения см. в разделе Точки следования.

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

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

Пример
В следующем примере демонстрируется оператор последовательного вычисления.

for ( i = j = 1; i + j < 20; i += i, j-- );

В этом примере каждый операнд третьего выражения оператора for вычисляется независимо. Сначала
вычисляется левый операнд i += i , а затем — правый, j-- .

func_one( x, y + 2, z );
func_two( (x--, y + 2), z );

В вызове функции func_one передаются три аргумента, разделенные запятыми: x , y + 2 и z . В вызове


функции func_two скобки заставляют компилятор интерпретировать первую запятую в качестве оператора
последовательного вычисления. В этом вызове функции в функцию func_two передаются два аргумента.
Первым аргументом является результат операции последовательного вычисления (x--, y + 2) , который
имеет значение и тип выражения y + 2 ; второй аргумент — z .

См. также
Оператор "запятая": ,
Преобразования типов (C)
13.10.2020 • 2 minutes to read • Edit Online

Преобразования типов зависят от указанного оператора и типа операнда или операторов.


Преобразования типов выполняются в следующих случаях:

Когда значение одного типа присваивается переменной другого типа или оператор преобразует
тип своего операнда или операндов до выполнения операции

Когда значение одного типа явно приводится к другому типу

Когда значение передается в качестве аргумента в функцию или когда тип возвращается из
функции

Символ, короткое целое число или целое битовое поле, со знаком или без, а также объект типа
перечисления можно использовать в выражении везде, где можно использовать целое число. Если int
может представлять все значения исходного типа, значение преобразуется в int ; в противном случае
оно преобразуется в unsigned int . Этот процесс называется "восходящим приведением целого типа".
Восходящее приведение целого типа сохраняет значение. То есть гарантируется, что значение после
приведения будет таким же, как до него. Дополнительные сведения есть в статье Обычные
арифметические преобразования.

См. также
Выражения и присваивания
Преобразования присваиваний
13.10.2020 • 2 minutes to read • Edit Online

В операциях присваивания тип присваиваемого значения преобразуется в тип переменной, которой


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

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

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

Преобразования типов с плавающей запятой

Преобразования в типы указателей и из типов указателей

Преобразования из других типов

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


присваивания нельзя использовать l-значение const .

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

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

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

int i = -3;
unsigned short u;

u = i;
printf_s( "%hu\n", u ); // Prints 65533

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

Сведения о размерах целочисленных типов и типов с плавающей запятой см. в статье Хранение базовых
типов.

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

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

В компиляторе Майкрософт int и long являются отдельными, но эквивалентными типами.


Преобразование значения int выполняется так же, как и преобразование long .

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

Таблица преобразований из целочисленных типов со знаком


ИСХОДНЫЙ ТИП КОМУ МЕТОД

char 1 short Расширение знака

char long Расширение знака

char long long Расширение знака

char unsigned char Сохранение шаблона; бит высокого


порядка перестает
функционировать как бит знака
ИСХОДНЫЙ ТИП КОМУ МЕТОД

char unsigned short Расширение знака до short ;


преобразование short в
unsigned short

char unsigned long Расширение знака до long ;


преобразование long в
unsigned long

char unsigned long long Расширение знака до long long ;


преобразование long long в
unsigned long long

char float Расширение знака до long ;


преобразование long в float

char double Расширение знака до long ;


преобразование long в double

char long double Расширение знака до long ;


преобразование long в double

short char Сохранение байта низкого порядка

short long Расширение знака

short long long Расширение знака

short unsigned char Сохранение байта низкого порядка

short unsigned short Сохранение битового шаблона; бит


высокого порядка перестает
функционировать как бит знака

short unsigned long Расширение знака до long ;


преобразование long в
unsigned long

short unsigned long long Расширение знака до long long ;


преобразование long long в
unsigned long long

short float Расширение знака до long ;


преобразование long в float

short double Расширение знака до long ;


преобразование long в double

short long double Расширение знака до long ;


преобразование long в double

long char Сохранение байта низкого порядка


ИСХОДНЫЙ ТИП КОМУ МЕТОД

long short Сохранение слова низкого порядка

long long long Расширение знака

long unsigned char Сохранение байта низкого порядка

long unsigned short Сохранение слова низкого порядка

long unsigned long Сохранение битового шаблона; бит


высокого порядка перестает
функционировать как бит знака

long unsigned long long Расширение знака до long long ;


преобразование long long в
unsigned long long

long float Представление в виде float . Если


long невозможно представить
точно, некоторая точность
теряется.

long double Представление в виде double . Если


long невозможно представить
точно в виде double , некоторая
точность теряется.

long long double Представление в виде double . Если


long невозможно представить
точно в виде double , некоторая
точность теряется.

long long char Сохранение байта низкого порядка

long long short Сохранение слова низкого порядка

long long long Сохранение младшего dword

long long unsigned char Сохранение байта низкого порядка

long long unsigned short Сохранение слова низкого порядка

long long unsigned long Сохранение младшего dword

long long unsigned long long Сохранение битового шаблона; бит


высокого порядка перестает
функционировать как бит знака

long long float Представление в виде float . Если


long long невозможно представить
точно, некоторая точность
теряется.
ИСХОДНЫЙ ТИП КОМУ МЕТОД

long long double Представление в виде double . Если


long long невозможно представить
точно в виде double , некоторая
точность теряется.

long long long double Представление в виде double . Если


long long невозможно представить
точно в виде double , некоторая
точность теряется.

1 Все записи char основаны на том, что тип char является типом со знаком по умолчанию.

См. также
Преобразования присваиваний
Преобразования из целочисленных типов без
знака
13.10.2020 • 4 minutes to read • Edit Online

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

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

unsigned k = 65533;
short j;

j = k;
printf_s( "%hd\n", j ); // Prints -3

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

Сведения о размерах целочисленных типов и типов с плавающей запятой см. в статье Хранение базовых
типов.

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

В компиляторе Майкрософт unsigned (или unsigned int ) и unsigned long являются отдельными, но
эквивалентными типами. Преобразование значения типа unsigned int выполняется так же, как и
преобразование unsigned long .

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

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

Таблица преобразований из целочисленных типов без знака


ИСХОДНЫЙ ТИП КОМУ МЕТОД

unsigned char char Сохранение битового шаблона; бит


высокого порядка становится битом
знака

unsigned char short Нулевое расширение

unsigned char long Нулевое расширение

unsigned char long long Нулевое расширение

unsigned char unsigned short Нулевое расширение


ИСХОДНЫЙ ТИП КОМУ МЕТОД

unsigned char unsigned long Нулевое расширение

unsigned char unsigned long long Нулевое расширение

unsigned char float Преобразование в long ;


преобразование long в float

unsigned char double Преобразование в long ;


преобразование long в double

unsigned char long double Преобразование в long ;


преобразование long в double

unsigned short char Сохранение байта низкого порядка

unsigned short short Сохранение битового шаблона; бит


высокого порядка становится битом
знака

unsigned short long Нулевое расширение

unsigned short long long Нулевое расширение

unsigned short unsigned char Сохранение байта низкого порядка

unsigned short unsigned long Нулевое расширение

unsigned short unsigned long long Нулевое расширение

unsigned short float Преобразование в long ;


преобразование long в float

unsigned short double Преобразование в long ;


преобразование long в double

unsigned short long double Преобразование в long ;


преобразование long в double

unsigned long char Сохранение байта низкого порядка

unsigned long short Сохранение слова низкого порядка

unsigned long long Сохранение битового шаблона; бит


высокого порядка становится битом
знака

unsigned long long long Нулевое расширение

unsigned long unsigned char Сохранение байта низкого порядка


ИСХОДНЫЙ ТИП КОМУ МЕТОД

unsigned long unsigned short Сохранение слова низкого порядка

unsigned long unsigned long long Нулевое расширение

unsigned long float Преобразование в long ;


преобразование long в float

unsigned long double Непосредственное преобразование в


double

unsigned long long double Преобразование в long ;


преобразование long в double

unsigned long long char Сохранение байта низкого порядка

unsigned long long short Сохранение слова низкого порядка

unsigned long long long Сохранение младшего dword

unsigned long long long long Сохранение битового шаблона; бит


высокого порядка становится битом
знака

unsigned long long unsigned char Сохранение байта низкого порядка

unsigned long long unsigned short Сохранение слова низкого порядка

unsigned long long unsigned long Сохранение младшего dword

unsigned long long float Преобразование в long ;


преобразование long в float

unsigned long long double Непосредственное преобразование в


double

unsigned long long long double Преобразование в long ;


преобразование long в double

См. также
Преобразования присваиваний
Преобразования типов с плавающей запятой
13.10.2020 • 7 minutes to read • Edit Online

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

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

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

Компиляторы Майкрософт используют представление binary32 согласно IEEE-754 для значений типа float
и представление binary64 для long double и double . Так как для long double и double используется одно
и то же представление, они имеют одинаковый диапазон и точность.

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

Для преобразования в целочисленный тип меньше long сначала значение преобразуется в тип long ,а
затем в результирующий тип.

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

Результатом может быть значение-метка, то есть представимое значение, максимально удаленное от


нуля. Для типов со знаком это наименьшее представимое значение (0x800...0). Для типов без знака
это наибольшее представимое значение (0xFF...F).

Результат может дополняться, то есть значение, которое слишком велико для представления,
преобразуется в наибольшее представимое значение, а значение, которое слишком мало для
представления, преобразуются в наименьшее представимое значение. Одно из этих двух значений
также используется в качестве значения-метки.

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

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

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


Таблица преобразования типов с плавающей запятой
ИСХОДНЫЙ ТИП КОМУ МЕТОД

float char Преобразование в long ;


преобразование long в char

float short Преобразование в long ;


преобразование long в short

float int Усечение до десятичной запятой.


Если результат слишком велик для
представления в качестве значения
int , результат не определен.

float long Усечение до десятичной запятой.


Если результат слишком велик для
представления в качестве значения
long , результат не определен.

float long long Усечение до десятичной запятой.


Если результат слишком велик для
представления в качестве значения
long long , результат не
определен.

float unsigned char Преобразование в long ;


преобразование long в
unsigned char

float unsigned short Преобразование в long ;


преобразование long в
unsigned short

float unsigned Усечение до десятичной запятой.


Если результат слишком велик для
представления в качестве значения
unsigned , результат не определен.

float unsigned long Усечение до десятичной запятой.


Если результат слишком велик для
представления в качестве значения
unsigned long , результат не
определен.

float unsigned long long Усечение до десятичной запятой.


Если результат слишком велик для
представления в качестве значения
unsigned long long , результат не
определен.

float double Представление в качестве значения


double .

float long double Представление в качестве значения


long double .
ИСХОДНЫЙ ТИП КОМУ МЕТОД

double char Преобразование в float ;


преобразование float в char

double short Преобразование в float ;


преобразование float в short

double int Усечение до десятичной запятой.


Если результат слишком велик для
представления в качестве значения
int , результат не определен.

double long Усечение до десятичной запятой.


Если результат слишком велик для
представления в качестве значения
long , результат не определен.

double unsigned char Преобразование в long ;


преобразование long в
unsigned char

double unsigned short Преобразование в long ;


преобразование long в
unsigned short

double unsigned Усечение до десятичной запятой.


Если результат слишком велик для
представления в качестве значения
unsigned , результат не определен.

double unsigned long Усечение до десятичной запятой.


Если результат слишком велик для
представления в качестве значения
unsigned long , результат не
определен.

double unsigned long long Усечение до десятичной запятой.


Если результат слишком велик для
представления в качестве значения
unsigned long long , результат не
определен.

double float Представление в качестве значения


float . Если значение double
невозможно точно представить с
типом float , происходит потеря
точности. Если значение слишком
велико для представления в
качестве значения float ,
результат не определен.

double long double Значение long double


рассматривается как double .

Преобразования из типа long double производятся так же, как из типа double .
См. также
Преобразования присваиваний
Преобразования в типы указателей и из типов
указателей
13.10.2020 • 3 minutes to read • Edit Online

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

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

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

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

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

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

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

Если размер целочисленного типа совпадает с размером типа указателя, преобразование просто
приводит к обработке целочисленного значения как указателя (целого числа без знака).

Если размер целочисленного типа отличается от размера типа указателя, сначала целочисленный
тип преобразуется в размер указателя по алгоритмам преобразования, которые указаны в таблицах
Преобразование из целочисленных типов со знаком и Преобразование из целочисленных типов без
знака, а затем рассматривается как значение указателя.

Константное целочисленное выражение со значением 0 или аналогичное выражение, приведенное к типу


void * , можно преобразовать в указатель любого типа путем приведения типов, присваивания или
сравнения. При этом создается пустой указатель, равный другому пустому указателю того же типа, но не
равный любому указателю на функцию или объект. Целые числа, отличные от константы 0, можно
преобразовать в тип указателя, но результат будет непереносимым.

См. также
Преобразования назначений
Преобразования из других типов
13.10.2020 • 2 minutes to read • Edit Online

Поскольку значение enum по определению имеет тип int , преобразования в тип enum и обратно
выполняются так же, как и для типа int . В компиляторе Microsoft C тип integer обрабатывается так же, как
и long .

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

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

Любое значение можно преобразовать в тип void , но результат такого преобразования можно
использовать только в контексте, в котором значение выражения отбрасывается, например в операторе
выражения.

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

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

См. также
Преобразования назначений
Преобразования приведений типов
13.10.2020 • 3 minutes to read • Edit Online

Приведения типов можно использовать для явного преобразования типов.

Синтаксис

cast-expression:
унарное выражение
( type-name ) cast-expression
type-name:
specifier-qualifier-list abstract-declaratoropt
type-name обозначает тип, а cast-expression содержит значение, которое требуется привести к этому
типу. Выражение с приведением типов не является L-значением. cast-expression преобразуется так, как
если бы оно было присвоено переменной с типом type-name. Правила преобразования при операциях
присваивания (которые описаны в статье Преобразования назначений) применяются и к приведению
типов. В следующей таблице показаны типы, которые могут приводиться к любому заданному типу.

Допустимые приведения типов


ЦЕЛЕВЫЕ ТИПЫ ПОТЕНЦИАЛЬНЫЕ ИСТОЧНИКИ

Целочисленные типы Любой целочисленный тип, тип с плавающей запятой


или указатель на объект

С плавающей запятой Любой арифметический тип

Указатель на объект , или ( void * ) Любой целочисленный тип, ( void * ), указатель на


объект или указатель функции

Указатель на функцию Любой целочисленный тип, указатель на объект или


указатель функции

Структура, объединение или массив Отсутствуют

Тип void Любой тип

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

Обратите внимание, что выражение void * содержит указатель типа void , а не void . Если объект
приводится к типу void , результирующее выражение невозможно присвоить элементу. Аналогично
объект приведения типа не является приемлемым L-значением, поэтому для такого объекта невозможно
выполнить присваивание.

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

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

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

Выражение можно преобразовать в тип void с помощью приведения, но результирующее выражение


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

См. также
Преобразования типов
Преобразования вызова функции
13.10.2020 • 2 minutes to read • Edit Online

Тип преобразования, выполняемого над аргументами в вызове функции, зависит от того, имеется ли для
вызываемой функции прототип функции (предварительное объявление) с объявленными типами
аргументов.

Если существует прототип функции и в нем объявлены типы аргументов, то компилятор выполняет
проверку типа (см. статью Функции).

Если прототипа нет , то над аргументами в вызове функции выполняются только обычные арифметические
преобразования. Для каждого аргумента в вызове они выполняются отдельно. Иными словами, значение
типа float преобразуется в double ; значение типа char или short — в int ; а unsigned char или
unsigned short — в unsigned int .

См. также
Преобразования типов
Операторы (C)
13.10.2020 • 2 minutes to read • Edit Online

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

Оператор break
Составной оператор
Оператор continue
Оператор do-while
Оператор-выражение

Оператор for
Оператор goto и операторы с метками
Оператор if
Оператор NULL
Оператор return

Оператор switch
Оператор try-except
Оператор try-finally
Оператор while

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

Операторы языка C состоят из токенов, выражений и других операторов. Оператор, который формирует
компонент или другой оператор, называется телом внешнего оператора. В этом разделе рассматриваются
все типы операторов, которые задаются следующим синтаксисом:

Синтаксис
statement: labeled-statement
compound-statement
expression-statement
selection-statement
iteration-statement
jump-statement
try-except-statement /* поддерживается только компилятором Майкрософт */
try-finally-statement /* поддерживается только компилятором Майкрософт */
Тело оператора часто представляет собой составной оператор, то есть состоит из других операторов,
которые могут содержать ключевые слова. Составные операторы разграничиваются фигурными скобками (
{ } ). Все остальные операторы C заканчиваются точкой с запятой ( ; ). Точка с запятой является признаком
конца оператора.

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

Любой оператор C может начинаться с метки-идентификатора, которая состоит из имени и двоеточия. Так
как метки операторов распознает только оператор goto , они рассматриваются в разделе, посвященном
оператору goto . Дополнительные сведения см. в статье goto и помеченные операторы (C).

См. также
Операторы
Оператор break (C)
13.10.2020 • 2 minutes to read • Edit Online

Оператор break завершает выполнение ближайшего внешнего оператора do , for , switch или while , в
котором он находится. Управление передается оператору, который расположен после завершенного
оператора.

Синтаксис
оператор-перехода:
break ;
Оператор break часто используется для заверения обработки определенного блока в операторе switch .
Если внешний оператор итерации или оператор switch отсутствует , создается ошибка.

Если используются вложенные операторы, то break завершает выполнение только того оператора do ,
for , switch или while , который непосредственно его окружает. Передать управление за пределы
вложенной структуры можно при помощи оператора return или goto .

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

#include <stdio.h>
int main() {
char c;
for(;;) {
printf_s( "\nPress any key, Q to quit: " );

// Convert to character value


scanf_s("%c", &c);
if (c == 'Q')
break;
}
} // Loop exits only when 'Q' is pressed

См. также
Оператор break
Составной оператор (C)
13.10.2020 • 2 minutes to read • Edit Online

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

Синтаксис
compound-statement:
{ declaration-listopt statement-listopt }
declaration-list:
declaration
declaration-list declaration
statement-list:
statement
statement-list statement
Если используются объявления, они должны задаваться до всех операторов. Область видимости каждого
идентификатора, объявленного в начале составной инструкции, начинается в точке его объявления и
завершается в конце блока. Она распространяется на весь блок, за исключением случаев, когда во
внутреннем блоке объявлен такой же идентификатор.

Предполагается, что идентификаторы в составном операторе имеют модификатор auto , если иное явно
не объявлено при помощи ключевых слов register , static или extern . Это не относится к функциям,
которые могут быть только extern . В объявлении функции можно опустить описатель extern , и функция
все равно будет extern .

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

При каждом входе в составной оператор выполняется повторное выделение памяти, а если нужно, то и
повторная инициализация, для переменных, объявленных в блоке с ключевым словом auto или register .
Эти переменные не определяются после выхода из составного оператора. Если внутри блока объявлена
переменная с атрибутом static , то она инициализируется один раз в начале выполнения программы и
сохраняет значение на протяжении всего выполнения программы. Дополнительные сведения о ключевом
слове static можно найти в статье Классы хранения.

Ниже показан пример составного оператора:

if ( i > 0 )
{
line[i] = x;
x++;
i--;
}

Если i в этом примере больше 0, то все инструкции внутри составного оператора выполняются в порядке
их расположения.
См. также
Операторы
Оператор continue (C)
13.10.2020 • 2 minutes to read • Edit Online

Оператор continue передает элемент управления в следующую итерацию ближайшего внешнего


оператора do , for или while , в которой она присутствует , минуя все оставшиеся операторы в теле
оператора do , for или while .

Синтаксис
оператор-перехода:
continue ;
Следующая итерация оператора do , for или while определяется следующим образом:

В операторе do или while следующая итерация начинается с повторного вычисления выражения


оператора do или while .

Оператор continue в операторе for приводит к вычислению выражения цикла оператора for .
Затем компилятор повторно вычисляет условное выражение и в зависимости от результата либо
завершает , либо выполняет итерацию тела оператора. Дополнительные сведения об операторе for
и его нетерминальных символах см. в статье Оператор for.

Ниже приводится пример оператора continue :

while ( i-- > 0 )


{
x = f( i );
if ( x == 1 )
continue;
y += x * x;
}

В этом примере тело оператора выполняется при i больше 0. Первой переменной f(i) присваивается
значение x ; затем, если x равно 1, выполняется оператор continue . Остальные операторы в теле
игнорируются, и выполнение возобновляется в начале цикла с вычисления теста цикла.

См. также
Оператор continue
Оператор do-while (C)
13.10.2020 • 2 minutes to read • Edit Online

Оператор do-while позволяет повторять простой или составной оператор, пока указанное выражение не
примет значение false.

Синтаксис
iteration-statement: do statement while ( expression ) ;
Выражение expression в операторе do-while вычисляется после выполнения тела цикла. Поэтому тело
цикла всегда выполняется по крайней мере один раз.

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

1. Выполняется тело оператора.


2. Затем вычисляется значение expression. Если выражение expression имеет значение false, выполнение
оператора do-while завершается и управление передается следующему оператору программы. Если
expression имеет значение true (то есть не равно нулю), процесс повторяется с шага 1.
Выполнение оператора do-while также прерывается, когда в теле оператора выполняется оператор break ,
goto или return .

Это пример оператора do-while:

do
{
y = f( x );
x--;
} while ( x > 0 );

В этом операторе do-while два оператора y = f( x ); и x--; выполняются независимо от начального


значения переменной x . Затем вычисляется выражение x > 0 . Если x больше 0, тело оператора
выполняется еще раз и снова вычисляется выражение x > 0 . Тело оператора многократно выполняется,
пока значение переменной x остается больше 0. Выполнение оператора do-while завершается, когда
значение переменной x становится равным 0 или отрицательным. Тело цикла выполняется по крайней
мере один раз.

См. также
Оператор do-while (C)
Оператор выражений (C)
15.05.2020 • 2 minutes to read • Edit Online

Когда выполняется оператор-выражение, соответствующее выражение оценивается по правилам,


описанным в статье Выражения и присваивания.

Синтаксис
expression-statement:
expressionopt ;
Все побочные эффекты от вычисления выражений выполняются до перехода к следующему оператору.
Пустой оператор выражения называется неопределенным оператором. Дополнительные сведения см. в
статье Оператор NULL (C).

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

x = ( y + 3 ); /* x is assigned the value of y + 3 */


x++; /* x is incremented */
x = y = 0; /* Both x and y are initialized to 0 */
proc( arg1, arg2 ); /* Function call returning void */
y = z = ( f( x ) + 3 ); /* A function-call expression */

В последней строке приводится пример выражения вызова функции. Значение этого выражения (т. е.
значение, возвращаемое функцией) увеличивается на 3, а затем присваивается обеим переменным: y и z .

См. также
Операторы
Оператор for (C)
13.10.2020 • 3 minutes to read • Edit Online

Оператор for позволяет повторить выполнение того или иного оператора или составного оператора
заданное число раз. Тело оператора for выполняется ноль или более раз, пока необязательное условие
не примет значение false. Внутри оператора for можно использовать необязательные выражения для
инициализации и изменения значений во время выполнения этого оператора ( for ).

Синтаксис
оператор-итерации:
for ( init-expressionнеоб. ; cond-expressionнеоб. ; loop-expressionнеоб. ) statement
Оператор for выполняется следующим образом:

1. Вычисляется выражение init-expression (если есть). Оно определяет инициализацию цикла. На тип
выражения init-expression ограничений не накладывается.

2. Вычисляется выражение cond-expression (если есть). Это выражение должно иметь арифметический
тип или тип указателя. Оно вычисляется перед каждой итерацией. Возможны три результата.

Если выражение cond-expression возвращает true (ненулевое значение), выполняется


оператор statement, после чего вычисляется выражение loop-expression (при его наличии).
Выражение loop-expression вычисляется после завершения каждой итерации. На его тип
ограничений не накладывается. Побочные эффекты выполняются по порядку. Затем процесс
начинается снова с вычисления выражения cond-expression.

Если выражение cond-expression опущено, оно (cond-expression) считается равным true, а


выполнение продолжается согласно описанию в предыдущем абзаце. Выполнение оператора
for без аргумента cond-expression завершается только при выполнении в его теле оператора
break или return либо при выполнении оператора перехода goto к оператору с меткой вне
тела оператора for .

Если выражение cond-expression имеет значение false (0), выполнение оператора for
завершается и управление передается следующему оператору программы.

Выполнение оператора for также завершается при выполнении в его теле оператора break , goto или
return . Оператор continue в цикле for задает дальнейшее вычисление выражения loop-expression. При
выполнении оператора break в цикле for выражение loop-expression не вычисляется и не выполняется.
Оператор

for( ; ; )

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

Пример
В следующем примере показано использование оператора for :
// c_for.c
int main()
{
char* line = "H e \tl\tlo World\0";
int space = 0;
int tab = 0;
int i;
int max = strlen(line);
for (i = 0; i < max; i++ )
{
if ( line[i] == ' ' )
{
space++;
}
if ( line[i] == '\t' )
{
tab++;
}
}

printf("Number of spaces: %i\n", space);


printf("Number of tabs: %i\n", tab);
return 0;
}

Вывод
Number of spaces: 4
Number of tabs: 2

См. также
Операторы
goto и помеченные операторы (C)
13.10.2020 • 2 minutes to read • Edit Online

Оператор goto передает управление метке. Данная метка должна находиться в той же функции и может
присутствовать только перед одним ее оператором.

Синтаксис
statement:
labeled-statement
jump-statement
оператор-перехода:
goto identifier ;
labeled-statement:
identifier : statement
Метка оператора значима только для оператора goto ; в любом другом контексте оператор с меткой
выполняется независимо от нее.

jump-statement должен находиться в той же функции и может присутствовать только перед одним ее
оператором. Набор имен identifier после оператора goto имеет свое собственное пространство имен,
поэтому эти имена не конфликтуют с другими идентификаторами. Повторное объявление меток
невозможно. Дополнительные сведения см. в статье Пространства имен.

Хорошим стандартом в программировании следует считать применение оператора break , continue и


return вместо goto во всех случаях, когда это возможно. Поскольку оператор break выполняет выход
только из одного уровня вложенности, для глубоко вложенных циклов может потребоваться оператор
goto .
В следующем примере показано использование оператора goto .
// goto.c
#include <stdio.h>

int main()
{
int i, j;

for ( i = 0; i < 10; i++ )


{
printf_s( "Outer loop executing. i = %d\n", i );
for ( j = 0; j < 3; j++ )
{
printf_s( " Inner loop executing. j = %d\n", j );
if ( i == 5 )
goto stop;
}
}

/* This message does not print: */


printf_s( "Loop exited. i = %d\n", i );

stop: printf_s( "Jumped to stop. i = %d\n", i );


}

В этом примере оператор goto передает управление в точку с меткой stop , когда значение переменной
i равно 5.

См. также
Операторы
Оператор if (C)
13.10.2020 • 3 minutes to read • Edit Online

Оператор if управляет условным ветвлением. Тело оператора if выполняется, если значение


выражения отлично от нуля. Существует две формы синтаксиса для оператора if .

Синтаксис
selection-statement: if ( expression ) statement
if ( expression ) statement else statement
В обоих формах оператора if выражение может иметь любое значение, кроме структуры, и его
вычисление влечет за собой все соответствующие побочные эффекты.

В первой форме синтаксиса оператор statement выполняется, если значение expression имеет значение true
(не равно нулю). Если выражение возвращает false, statement пропускается. Во второй форме синтаксиса c
else , если expression имеет значение false, выполняется второй оператор statement. После этого
управление передается (в обеих формах) из оператора if в следующий по порядку оператор программы,
если выполняемый оператор не содержит операторов break , continue или goto .

Ниже приведены примеры операторов if :

if ( i > 0 )
y = x / i;
else
{
x = i;
y = f( x );
}

В этом примере оператор y = x/i; выполняется, если i больше 0. Если значение i меньше или равно 0,
значение i присваивается переменной x , а значение f( x ) присваивается переменной y . Обратите
внимание, что оператор, образующий предложение if , заканчивается точкой с запятой.

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

if ( i > 0 ) /* Without braces */


if ( j > i )
x = j;
else
x = i;

В этом примере предложение else сопоставляется с внутренним оператором if . Если значение i


меньше или равно 0, переменной x не присваивается никакого значения.
if ( i > 0 )
{ /* With braces */
if ( j > i )
x = j;
}
else
x = i;

В этом примере благодаря фигурным скобкам, окружающим внутренний оператор if , предложение else
относится к внешнему оператору if . Если значение i меньше или равно 0, значение переменной i
присваивается переменной x .

См. также
Оператор if-else (C++)
Оператор NULL (C)
13.10.2020 • 2 minutes to read • Edit Online

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

Синтаксис
;

Примечания
Некоторые операторы, например do , for , if и while , требуют , чтобы исполняемые операторы были
представлены в теле оператора. Оператор null соответствует синтаксическим требованиям в случаях,
когда существенная основная часть оператора не требуется.

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

В следующем примере показан оператор null.

for ( i = 0; i < 10; line[i++] = 0 )


;

Здесь выражение цикла в операторе for line[i++] = 0 инициализирует первые 10 элементов line
значением 0. Основная часть оператора представляет собой оператор null, поскольку остальные
операторы не требуются.

См. также
Операторы
Оператор return (C)
13.10.2020 • 7 minutes to read • Edit Online

Оператор return завершает выполнение функции и возвращает управление вызывающей функции.


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

Синтаксис
оператор_перехода:
return выражение( необязательно ) ;

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

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

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

Многие программисты заключают аргумент выражения в операторе return в скобки. Однако использовать
эти скобки в языке C необязательно.

Если компилятор обнаруживает операторы, размещенные после return , он может вывести


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

В функции main оператор return и выражение являются необязательными. То, что происходит с
указанным возвращаемым значением, зависит от реализации. Только для систем Майкрософт :
реализация C от Майкрософт возвращает значение выражения процессу, вызвавшему программу, например
cmd.exe . Если выражение return не указано , среда выполнения C от Майкрософт возвращает значение,
соответствующее успешному (0) или неудачному (ненулевое значение) выполнению.

Пример
В этом примере показана одна программа из нескольких частей. Она демонстрирует оператор return и
использование его для завершения выполнения функции и, при необходимости, возврата какого-то
значения.
// C_return_statement.c
// Compile using: cl /W4 C_return_statement.c
#include <limits.h> // for INT_MAX
#include <stdio.h> // for printf

long long square( int value )


{
// Cast one operand to long long to force the
// expression to be evaluated as type long long.
// Note that parentheses around the return expression
// are allowed, but not required here.
return ( value * (long long) value );
}

Функция square возвращает квадрат своего аргумента, используя более широкий тип для избежания
арифметической ошибки. Только для систем Майкрософт : в реализации C от Майкрософт тип
long long достаточно велик, чтобы вмещать произведение двух значений int без переполнения.

Скобки вокруг выражения return в функции square вычисляются как часть выражения, и использовать их
в операторе return не требуется.

double ratio( int numerator, int denominator )


{
// Cast one operand to double to force floating-point
// division. Otherwise, integer division is used,
// then the result is converted to the return type.
return numerator / (double) denominator;
}

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

void report_square( void )


{
int value = INT_MAX;
long long squared = 0LL;
squared = square( value );
printf( "value = %d, squared = %lld\n", value, squared );
return; // Use an empty expression to return void.
}

Функция report_square вызывает square со значением параметра INT_MAX — самым большим целым
числом со знаком, которое помещается в int . Результат типа long long сохраняется в squared , а затем
выдается в выводе. Функция report_square имеет тип возвращаемого значения void , поэтому она не
содержит выражения в операторе return .

void report_ratio( int top, int bottom )


{
double fraction = ratio( top, bottom );
printf( "%d / %d = %.16f\n", top, bottom, fraction );
// It's okay to have no return statement for functions
// that have void return types.
}

Функция report_ratio вызывает ratio со значениями параметров 1 и INT_MAX . Результат типа double
сохраняется в fraction , а затем выдается в выводе. Функция report_ratio имеет тип возвращаемого
значения void , поэтому явно возвращать значение не требуется. Выполнение report_ratio не дает
результата и не возвращает вызывающей функции никакого значения.

int main()
{
int n = 1;
int x = INT_MAX;

report_square();
report_ratio( n, x );

return 0;
}

Функция main вызывает две функции: report_square и report_ratio . Поскольку report_square не принимает
параметров и возвращает void , результат не присваивается переменной. Аналогичным образом функция
report_ratio возвращает void , поэтому ее возвращаемое значение тоже не сохраняется. После вызова
каждой из этих функций выполнение продолжается в следующем операторе. Затем main возвращает
значение 0 (обычно свидетельствующее об успешном выполнении), чтобы завершить программу.

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

cl /W4 C_return_statement.c

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

value = 2147483647, squared = 4611686014132420609


1 / 2147483647 = 0.0000000004656613

См. также
Операторы
Оператор :::no-loc(switch)::: (C)
13.10.2020 • 6 minutes to read • Edit Online

Операторы :::no-loc(switch)::: и :::no-loc(case)::: помогают управлять сложными условными


операциями и операциями ветвления. Оператор :::no-loc(switch)::: передает управление в оператор
внутри своего тела.

Синтаксис
selection-statement :
:::no-loc(switch)::: ( expression ) statement

labeled-statement :
:::no-loc(case)::: constant-expression : statement
:::no-loc(default)::: : statement

Примечания
Оператор :::no-loc(switch)::: передает управление одному из labeled-statement в своем теле в
зависимости от значения expression .

Значения expression и значение каждого constant-expression должны иметь целочисленный тип.


Выражение constant-expression должно иметь однозначное константное целочисленное значение во время
компиляции.

Управление передается оператору :::no-loc(case)::: , значение constant-expression которого


соответствует значению выражения expression . Оператор :::no-loc(switch)::: может содержать
неограниченное число экземпляров :::no-loc(case)::: . Однако значения ни одной из пар выражений
constant-expression в одном операторе :::no-loc(switch)::: не должны совпадать. Выполнение тела
оператора :::no-loc(switch)::: начинается с первого соответствующего оператора labeled-statement или
после него. Выполнение продолжается до конца тела оператора или пока оператор :::no-loc(break)::: не
передаст управление за пределы тела.

Оператор :::no-loc(switch)::: обычно используется следующим образом:

:::no-loc(switch)::: ( expression )
{
// declarations
// . . .
:::no-loc(case)::: constant_expression:
// statements executed if the expression equals the
// value of this constant_expression
:::no-loc(break):::;
:::no-loc(default)::::
// statements executed if expression does not equal
// any :::no-loc(case)::: constant_expression
}

Оператор :::no-loc(break)::: можно использовать для завершения обработки определенного оператора с


меткой в операторе :::no-loc(switch)::: . Он выполняет ветвление до конца оператора
:::no-loc(switch)::: . Без оператора выполнение программы продолжается до
:::no-loc(break):::
следующего оператора с меткой. Операторы будут выполняться до достижения оператора
:::no-loc(break)::: или конца всего оператора. В некоторых случаях может требоваться именно такое
поведение.

Оператор :::no-loc(default)::: выполняется, если ни одно из значений :::no-loc(case):::


constant-expression не равно значению expression . Если оператор :::no-loc(default)::: не указан и
соответствующий вариант :::no-loc(case)::: не найден, ни один из операторов в теле оператора
:::no-loc(switch)::: не выполняется. Допускается не более одного оператора :::no-loc(default)::: .
Оператор :::no-loc(default)::: не обязательно должен находиться в конце. Он может располагаться в
любом месте тела оператора :::no-loc(switch)::: . Метка :::no-loc(case)::: или :::no-loc(default):::
может располагаться только внутри оператора :::no-loc(switch)::: .

Выражения :::no-loc(switch)::: expression и :::no-loc(case)::: constant-expression должны быть


целочисленного типа. Значение каждого :::no-loc(case)::: constant-expression в теле оператора должно
быть уникальным.

Метки :::no-loc(case)::: и :::no-loc(default)::: тела оператора :::no-loc(switch)::: имеют значения


только при начальной проверке, которая определяет , с какого места тела оператора начинается
выполнение. Операторы :::no-loc(switch)::: могут быть вложенными. Любые статические переменные
инициализируются до выполнения любых операторов :::no-loc(switch)::: .

NOTE
Объявления могут располагаться в начале составного оператора, образующего тело оператора
:::no-loc(switch)::: , но инициализации, включенные в объявления, не выполняются. Оператор
:::no-loc(switch)::: передает управление непосредственно в выполняемый оператор в теле, минуя все строки,
содержащие инициализации.

В следующих примерах кода показаны операторы :::no-loc(switch)::: :

:::no-loc(switch):::( c )
{
:::no-loc(case)::: 'A':
capital_a++;
:::no-loc(case)::: 'a':
letter_a++;
:::no-loc(default)::: :
total++;
}

В этом примере, если переменная c равна 'A' , выполняются все три оператора тела :::no-loc(switch)::: ,
так как оператор :::no-loc(break)::: перед следующим оператором :::no-loc(case)::: отсутствует.
Управления передается первому оператору ( capital_a++; ) и продолжается по-порядку во всей остальной
части тела. Если переменная c равна 'a' , увеличиваются значения переменных letter_a и total . Если
переменная c не равна 'A' или 'a' , увеличивается только значение переменной total .
:::no-loc(switch):::( i )
{
:::no-loc(case)::: -1:
n++;
:::no-loc(break):::;
:::no-loc(case)::: 0 :
z++;
:::no-loc(break):::;
:::no-loc(case)::: 1 :
p++;
:::no-loc(break):::;
}

В этом примере оператор :::no-loc(break)::: указан после каждого оператора тела :::no-loc(switch)::: .
Оператор :::no-loc(break)::: вызывает принудительный выход из тела оператора после выполнения
одного оператора. Если переменная i равна –1, увеличивается только значение переменной n . Оператор
:::no-loc(break)::: после оператора n++; передает управление за пределы тела оператора, минуя
оставшиеся операторы. Аналогично, если переменная i равна 0, увеличивается только значение
переменной z ; если переменная i равна 1, увеличивается только значение переменной p .
Заключительный оператор :::no-loc(break)::: , строго говоря, не требуется, так как управление
передается из тела в конце составного оператора. Он добавлен для единообразия.

Один оператор может содержать несколько меток :::no-loc(case)::: , как показано в следующем примере:

:::no-loc(switch):::( c )
{
:::no-loc(case)::: 'a' :
:::no-loc(case)::: 'b' :
:::no-loc(case)::: 'c' :
:::no-loc(case)::: 'd' :
:::no-loc(case)::: 'e' :
:::no-loc(case)::: 'f' : convert_hex(c);
}

В этом примере, если константное выражение равно любой букве в диапазоне от 'a' до 'f' , вызывается
функция convert_hex .

Специально для систем Майкрософт


Microsoft C не ограничивает количество значений :::no-loc(case)::: в операторе :::no-loc(switch)::: .
Это число ограничивается только объемом доступной памяти. ANSI C требует , чтобы в операторе
:::no-loc(switch)::: можно было использовать не менее 257 меток :::no-loc(case)::: .

В Microsoft C расширения Майкрософт по умолчанию (:::no-loc(default):::) включены. Используйте параметр


компилятора /Za для отключения этих расширений.

См. также
Оператор :::no-loc(switch)::: (C++)
Оператор try-except (C)
13.10.2020 • 5 minutes to read • Edit Online

Только для систем Майкрософт

Оператор try-except является расширением Майкрософт для языка C, которое позволяет приложениям
получать управление программой при возникновении событий, обычно приводящих к прекращению
выполнения. Такие события вызываются исключениями, а механизм, предназначенный для работы с ними,
называется структурированной обработкой исключений.

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

Синтаксис
try-except-statement :
  __try compound-statement __except ( expression ) compound-statement

Составной оператор после предложения __try — это защищенный раздел. Составной оператор после
предложения __except — это обработчик исключений. Обработчик определяет набор действий,
предпринимаемых при возникновении исключения во время выполнения защищенного раздела.
Выполнение происходит следующим образом:

1. Сначала выполняется защищенный раздел.


2. Если исключение при этом не возникает , выполнение переходит в инструкцию, стоящую после
предложения __except .

3. Если исключение возникло во время выполнения защищенного раздела или в любой процедуре,
вызываемой защищенным разделом, вычисляется выражение __except . Способ обработки
исключения определяется возвращенным значением. Возможны три значения.

. Исключение не распознано. Программа переходит к поиску


EXCEPTION_CONTINUE_SEARCH
обработчика в стеке (сначала находятся выражения с оператором try-except , а затем
обработчики со следующим наивысшим приоритетом).

EXCEPTION_CONTINUE_EXECUTION . Исключение распознано, но отклонено. Выполнение


продолжается в точке, в которой возникло исключение.

EXCEPTION_EXECUTE_HANDLERИсключение распознано. Управление передается в обработчик


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

Так как выражение __except вычисляется как выражение C, оно ограничивается одиночным значением,
оператором условного выражения или оператором "запятая". Если требуется более сложная обработка,
выражение может вызывать процедуру, которая возвращает одно из этих трех значений.
NOTE
Структурированная обработка исключений поддерживается с исходными файлами C и C++. Но она не
предназначена специально для C++. Для переносимых программ C++ вместо структурированной обработки
исключений следует использовать обработку исключений C++. Кроме того, механизм обработки исключений
C++ обеспечивает намного более высокую гибкость, поскольку может обрабатывать исключения любого типа.
Дополнительные сведения см. в разделе Обработка исключений в справочнике по языку C++ .

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

В блоке операторов __leave можно использовать ключевое слово try-except . Результат использования
__leave — переход в конец блока try-except . Выполнение продолжается после окончания обработчика
исключений. Хотя для получения того же результата можно использовать оператор goto , он (оператор
goto ) приводит к освобождению стека. Оператор __leave более эффективен, так как он не вызывает
раскрутку стека.

Выход из оператора try-except с помощью функции времени выполнения longjmp считается


ненормальным завершением. Переход к оператору __try недопустим, но выход из него допускается.
Обработчик исключений не вызывается, если процесс удаляется во время выполнения оператора
try-except .

Пример
Ниже приведен пример обработчика исключений и обработчика завершения. Дополнительные сведения
об обработчиках завершения см. в разделе Оператор try-finally (С ).

.
.
.
puts("hello");
__try {
puts("in try");
__try {
puts("in try");
RAISE_AN_EXCEPTION();
} __finally {
puts("in finally");
}
} __except( puts("in filter"), EXCEPTION_EXECUTE_HANDLER ) {
puts("in except");
}
puts("world");

Ниже показаны выходные данные для этого примера с комментариями справа:

hello
in try /* fall into try */
in try /* fall into nested try */
in filter /* execute filter; returns 1 so accept */
in finally /* unwind nested finally */
in except /* transfer control to selected handler */
world /* flow out of handler */

КОНЕЦ Только для систем Майкрософт


См. также раздел
Оператор try-except (C++)
Оператор try-finally (C)
13.10.2020 • 4 minutes to read • Edit Online

Только для систем Майкрософт

Оператор try-finally является расширением Microsoft для языка C и позволяет приложениям


гарантировать выполнение кода очистки при прерывании выполнения блока кода. Очистка включает
такие задачи, как отмена распределения памяти, закрытие файлов и освобождение их дескрипторов.
Оператор try-finally особенно полезен для подпрограмм, в которых в нескольких местах выполняется
проверка на наличие ошибок, способных вызвать преждевременное возвращение из подпрограммы.

try-finally-statement :
  __try compound-statement __finally compound-statement

Составной оператор после предложения __try — это защищенный раздел. Составной оператор после
предложения __finally является обработчиком завершения. Такой обработчик определяет набор
действий, выполняемых при выходе из защищенного раздела, независимо от того, происходит ли выход в
результате исключения (ненормальное завершение) или в результате стандартной передачи управления
дальше (нормальное завершение).

Управление переходит к оператору __try в процессе обычного последовательного выполнения


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

1. Сначала выполняется защищенный раздел.


2. Вызывается обработчик завершения.
3. По окончании работы обработчика завершения выполнение продолжается после оператора
__finally . Независимо от того , как завершается защищенный раздел (например, оператором
выхода из защищенного тела goto или оператором return ), перед выходом потока управления из
защищенного раздела выполняется обработчик завершения.

В блоке операторов __leave можно использовать ключевое слово try-finally . Результат использования
__leave — переход в конец блока try-finally . Сразу же выполняется обработчик завершения. Хотя для
получения того же результата можно использовать оператор goto , он (оператор goto ) приводит к
освобождению стека. Оператор __leave более эффективен, так как он не вызывает раскрутку стека.

Выход из оператора try-finally с помощью оператора return или функции longjmp во время
выполнения считается ненормальным завершением. Переход к инструкции __try недопустим, но выход из
него допускается. Все операторы __finally , которые активны между исходной точкой и точкой
назначения, должны быть выполнены. Это называется локальной раскруткой.

Если при выполнении оператора try-finally процесс удаляется, обработчик завершения не вызывается.
NOTE
Структурированная обработка исключений поддерживается с исходными файлами C и C++. Но она не
предназначена специально для C++. Для переносимых программ C++ вместо структурированной обработки
исключений следует использовать обработку исключений C++. Кроме того, механизм обработки исключений
C++ обеспечивает намного более высокую гибкость, поскольку может обрабатывать исключения любого типа.
Дополнительные сведения см. в разделе Обработка исключений в справочнике по языку C++ .

Чтобы увидеть, как работает оператор try-finally , см. пример для оператора try-except .
КОНЕЦ Только для систем Майкрософт

См. также раздел


Оператор try-finally (C++)
Оператор while (C)
13.10.2020 • 2 minutes to read • Edit Online

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

Синтаксис
оператор-итерации:
while ( expression ) statement
Выражение expression должно иметь арифметический тип или тип указателя. Выполнение происходит
следующим образом:

1. Вычисляется значение expression.


2. Если выражение expression изначально ложно, тело оператора whileне выполняется ни одного раза,
а управление передается от оператора while следующему оператору в программе.

Если expression имеет значение True (то есть не равно нулю), выполняется тело оператора и процесс
повторяется с шага 1.

Выполнение оператора while прерывается, если в теле оператора выполняется оператор break , goto или
return . Для прерывания итерации без выхода из цикла while используйте оператор continue . Оператор
continue передает управление в следующую итерацию оператора while .

Ниже приводится пример оператора while :

while ( i >= 0 )
{
string1[i] = string2[i];
i--;
}

В этом примере производится копирование символов из string2 в string1 . Если значение i больше или
равно 0, значение string2[i] присваивается элементу string1[i] и значение переменной i уменьшается
на единицу. Когда значение переменной i становится равным 0 (или меньше 0), выполнение оператора
while прекращается.

См. также
Оператор while (C++)
Функции (C)
07.05.2020 • 2 minutes to read • Edit Online

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

Overview of Functions (Общие сведения о функциях)


Function Attributes (Атрибуты функций)
Specifying Calling Conventions (Указание соглашений о вызовах)
Inline Functions (Встраиваемые функции)
DLL Import and Export Functions (Функции экспорта и импорта библиотек DLL)
Naked Functions (Функции naked)
Storage Class (Класс хранения)
Return Type (Возвращаемый тип)
Аргументы

Параметры

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

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

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

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

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


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

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

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

double old_style(); /* Obsolete function declaration */

double alt_style( a , real ) /* Obsolete function definition */


double *real;
int a;
{
return ( *real + a ) ;
}

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

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


использованием многоточия, теперь выдают ошибку при выполнении компиляции с параметром /Za и
предупреждение четвертого уровня при выполнении компиляции с параметром /Ze. Пример:

void funct1( a, ... ) /* Generates a warning under /Ze or */


int a; /* an error when compiling with /Za */
{
}

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

void funct1( int a, ... )


{
}

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

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

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

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

Синтаксис
translation-unit:
external-declaration
translation-unit external-declaration
external-declaration: /* Допускается только в области видимости файла (внешней) */
function-definition
declaration
function-definition:
declaration-specifiersopt attribute-seqopt declarator declaration-listopt compound-statement
/* attribute-seq поддерживается только компилятором Майкрософт */
Параметры прототипа:

declaration-specifiers:
storage-class-specifier declaration-specifiersopt
type-specifier declaration-specifiersopt
type-qualifier declaration-specifiersopt
declaration-list:
declaration
declaration-list declaration
declarator:
pointeropt direct-declarator
direct-declarator: /* Декларатор функции */
direct-declarator ( parameter-type-list ) /* Декларатор нового стиля */
direct-declarator ( identifier-listopt ) /* Декларатор устаревшего стиля */
Для списка параметров в определении используется следующий синтаксис:

parameter-type-list: /* Список параметров */


parameter-list
parameter-list , ...
parameter-list:
parameter-declaration
parameter-list , parameter-declaration
parameter-declaration:
declaration-specifiers declarator
declaration-specifiers abstract-declaratoropt
В определении функции устаревшего стиле для списка параметров используется следующий синтаксис:

identifier-list: /* Используется в определениях и объявлениях функций устаревшего стиля */


identifier
identifier-list , identifier
Синтаксис тела функции:

compound-statement:
{ declaration-listopt statement-listopt }
Изменять объявления функций могут только описатели класса хранения extern и static . Описатель
extern означает , что на функцию можно ссылаться из других файлов; то есть, имя функции
экспортируется в компоновщик. Описатель static означает , что на функцию невозможно ссылаться из
других файлов. Имя такой функции не экспортируется компоновщиком. Если в определении функции
класс хранения не указан, принимается класс extern . В любом случае функция всегда видна от точки
определения до конца файла.

Сочетание необязательных деклараторов declaration-specifiers и обязательного декларатора declarator


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

Декларатор direct-declarator (в синтаксисе declarator) указывает имя определяемой функции и


идентификаторы ее параметров. Если direct-declarator содержит список parameter-type-list, в нем
определяются типы всех параметров. Такой декларатор также является прототипом функции для ее
последующих вызовов.

Элемент declaration в списке declaration-list в определении функции не может содержать других


описателей storage-class-specifier, кроме register . Описатель type-specifier в синтаксисе declaration-
specifiers можно опустить только в случае, если для типа int указан класс хранения register .
compound-statement представляет собой тело функции, где размещаются объявления локальных
переменных, ссылки на внешние объявленные элементы и операторы.

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


хранения, Тип возвращаемого значения, Параметры и Текст функции.

См. также
Функции
Атрибуты функций
13.10.2020 • 2 minutes to read • Edit Online

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

Необязательная нетерминальная attribute-seq позволяет выбирать соглашения о вызовах на уровне


функций. Можно также задать функции как __fastcall или __inline .

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

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

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

Дополнительные сведения по соглашениям о вызовах см. в разделе Разделы соглашений о вызовах.

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

См. также
Атрибуты функций
Встраиваемые функции
13.10.2020 • 2 minutes to read • Edit Online

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

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

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

Используйте следующую форму для определения встраиваемой функции:

__inline типнеоб. определение функции

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

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

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

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

Функции, в которых используется ключевое слово __inline , не следует путать со встраиваемым кодом на
языке ассемблера. Дополнительные сведения см. в статье о встроенном ассемблере.

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

См. также
inline, __inline, __forceinline
Встроенный ассемблер (C)
13.10.2020 • 2 minutes to read • Edit Online

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

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


программы С без дополнительных шагов по сборке и компоновке. Встроенный код на ассемблере встроен в
компилятор, поэтому вам не требуется отдельный сборщик для языка ассемблера, такой как Microsoft
Macro Assembler (MASM).
Так как встроенный ассемблер не требует отдельных действий по сборке и компоновке, он является более
удобным, чем отдельный ассемблер. Во встроенном коде на языке ассемблера можно использовать любое
имя переменной или функции языка C, находящееся в области видимости, поэтому его легко интегрировать
с кодом C программы. Поскольку в коде на языке ассемблера можно одновременно использовать
операторы C, с его помощью можно выполнять задачи, которые слишком сложно или невозможно
выполнить только в C.

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

Следующий код — это простой блок __asm , заключенный в фигурные скобки. (Этот код является
последовательностью пролога пользовательской функции.)

__asm
{
push ebp
mov ebp, esp
sub esp, __LOCAL_SIZE
}

Кроме того, можно поставить __asm перед каждой инструкцией по сборке:

__asm push ebp


__asm mov ebp, esp
__asm sub esp, __LOCAL_SIZE

Поскольку ключевое слово __asm является разделителем операторов, можно также помещать инструкции
ассемблера на одной строке:

__asm push ebp __asm mov ebp, esp __asm sub esp, __LOCAL_SIZE

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

См. также
Атрибуты функций
Функции импорта и экспорта DLL
13.10.2020 • 2 minutes to read • Edit Online

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

Наиболее полную и актуальную информацию по этой теме можно найти в статье dllexport, dllimport.

Модификаторы класса хранения dllimport и dllexport — это расширения языка С для систем Microsoft.
Эти модификаторы явным образом определяют интерфейс библиотеки DLL к ее клиенту (исполняемому
файлу или другой библиотеке DLL). Объявление функции в качестве dllexport позволяет обойтись без
файла определения модуля (.DEF). Кроме того, модификаторы dllimport и dllexport можно использовать
с данными и объектами.

Модификаторы класса хранения dllimport и dllexport должны использоваться с ключевым словом


расширенного синтаксиса атрибутов __declspec , как показано в следующем примере:

#define DllImport __declspec( dllimport )


#define DllExport __declspec( dllexport )

DllExport void func();


DllExport int i = 10;
DllExport int j;
DllExport int n;

Дополнительные сведения о синтаксисе расширенных модификаторов класса хранения см. в статье C


Extended Storage-Class Attributes (Расширенные атрибуты классов хранения C).
Завершение блока , относящегося только к системам Майкрософт

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

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

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

#define DllImport __declspec( dllimport )


#define DllExport __declspec( dllexport )

DllImport int func() /* Error; dllimport prohibited in */


/* definition. */
{
return 1;
}

Показанный ниже код также вызовет ошибку.

#define DllImport __declspec( dllimport )


#define DllExport __declspec( dllexport )

DllImport int i = 10; /* Error; this is a definition. */

Однако следующий синтаксис правильный.

#define DllImport __declspec( dllimport )


#define DllExport __declspec( dllexport )

DllExport int i = 10; /* Okay: this is an export definition. */

Использование атрибута dllexport подразумевает определение, а dllimport — объявление. Для


обеспечения объявления ключевое слово extern следует использовать с dllexport ; в противном случае
подразумевается определение.

#define DllImport __declspec( dllimport )


#define DllExport __declspec( dllexport )

extern DllImport int k; /* These are correct and imply */


Dllimport int j; /* a declaration. */

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

См. также
Функции импорта и экспорта DLL
Определение подставляемых функций C с
использованием dllexport и dllimport
13.10.2020 • 2 minutes to read • Edit Online

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

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

В качестве встроенной можно также определить функцию, объявленную с атрибутом dllimport . В этом
случае функцию можно расширить (согласно спецификации параметров компилятора /Ob (inline)), но ее
экземпляр никогда не создается. В частности, если принимается адрес встроенной импортированной
функции, возвращается адрес функции, находящейся в библиотеке DLL. Это поведение аналогично
получению адреса невстроенной импортированной функции.

Локальные статические данные и строки во встроенных функциях поддерживают одинаковые


идентификаторы между библиотекой DLL и клиентом так, как это было бы в одной программе (т. е.
исполняемый файл без интерфейса DLL).

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


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

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

См. также
Функции импорта и экспорта DLL
Правила и ограничения dllimport/dllexport
13.10.2020 • 3 minutes to read • Edit Online

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

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

Если в одном и том же модуле вашей программы содержатся объявления одной и той же функции с
атрибутами dllimport и dllexport , то атрибут dllexport имеет приоритет над dllimport . Однако
компилятор создает предупреждение. Пример:

#define DllImport __declspec( dllimport )


#define DllExport __declspec( dllexport )

DllImport void func1( void );


DllExport void func1( void ); /* Warning; dllexport */
/* takes precedence. */

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


объявленного с атрибутом dllimport . Например, следующий код вызывает ошибки:

#define DllImport __declspec( dllimport )


#define DllExport __declspec( dllexport )

DllImport int i;
.
.
.
int *pi = &i; /* Error */

void func2()
{
static int *pi = &i; /* Error */
}

Если при инициализации указателя на статическую функцию вы присвоите ему адрес функции,
объявленной с атрибутом dllimport , то указатель будет ссылаться не на адрес функции, а на адрес
преобразователя импорта DLL (это заглушка, которая передает управление функции). Следующее
присваивание не порождает сообщения об ошибке:
#define DllImport __declspec( dllimport )
#define DllExport __declspec( dllexport )

DllImport void func1( void


.
.
.
static void ( *pf )( void ) = &func1; /* No Error */

void func2()
{
static void ( *pf )( void ) = &func1; /* No Error */
}

Поскольку программа с атрибутом dllexport в объявлении объекта должна содержать определение


этого объекта, то указатель на глобальную или локальную статическую функцию можно
инициализировать с адресом функции с атрибутом dllexport . Аналогичным образом указатель на
глобальные или локальные статические данные можно инициализировать с адресом объекта данных
с атрибутом dllexport . Пример:

#define DllImport __declspec( dllimport )


#define DllExport __declspec( dllexport )

DllImport void func1( void );


DllImport int i;

DllExport void func1( void );


DllExport int i;
.
.
.
int *pi = &i; /* Okay */
static void ( *pf )( void ) = &func1; /* Okay */

void func2()
{
static int *pi = i; /* Okay */
static void ( *pf )( void ) = &func1; /* Okay */
}

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

См. также
Функции импорта и экспорта DLL
Функции Naked
07.05.2020 • 2 minutes to read • Edit Online

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

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

Поскольку атрибут naked относится только к определению функции и не является модификатором типа, в
функциях с этим атрибутом используется расширенный синтаксис атрибутов, который описывается в
статье Расширенные атрибуты классов хранения в C.

В следующем примере определяется функция с атрибутом naked .

__declspec( naked ) int func( formal_parameters )


{
/* Function body */
}

Другой пример:

#define Naked __declspec( naked )

Naked int func( formal_parameters )


{
/* Function body */
}

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

__declspec( naked ) int i; /* Error--naked attribute not */


/* permitted on data declarations. */

Атрибут naked относится только к определению функции и не может быть определен в прототипе
функции. Следующее объявление создает ошибку компилятора:

__declspec( naked ) int func(); /* Error--naked attribute not */


/* permitted on function declarations. */ \

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

См. также
Определения функций в C
Правила и ограничения при использовании
функций Naked
07.05.2020 • 2 minutes to read • Edit Online

Дополнительные сведения о правилах и ограничениях при использовании функций с атрибутом naked см. в
следующей статье справочника по языку С ++: Правила и ограничения для функций с атрибутом naked.

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

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

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

Схема кадра CStack


В данном примере показан стандартный код пролога, который может присутствовать в 32-разрядной
функции.

push ebp ; Save ebp


mov ebp, esp ; Set stack frame pointer
sub esp, localbytes ; Allocate space for locals
push <registers> ; Save registers

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

pop <registers> ; Restore registers


mov esp, ebp ; Restore stack pointer
pop ebp ; Restore ebp
ret ; Return from function

Стек всегда расширяется в направлении вниз (от старших адресов памяти к младшим). Указатель базы ( ebp )
указывает на помещенное в стек значение ebp . Область локальных переменных начинается с ebp-2 . Для
доступа к локальным переменным необходимо вычислить смещение от ebp путем вычитания
соответствующего значения из ebp .

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

Значение константы __LOCAL_SIZE определяется компилятором. Это значение представляет общее


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

mov eax, __LOCAL_SIZE ;Immediate operand--Okay


mov eax, [ebp - __LOCAL_SIZE] ;Error
В следующем примере функции naked с пользовательскими последовательностями пролога и эпилога
константа __LOCAL_SIZE используется в последовательности пролога.

__declspec ( naked ) func()


{
int i;
int j;

__asm /* prolog */
{
push ebp
mov ebp, esp
sub esp, __LOCAL_SIZE
}

/* Function body */

__asm /* epilog */
{
mov esp, ebp
pop ebp
ret
}
}

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

См. также
Функции naked
Класс хранения
13.10.2020 • 3 minutes to read • Edit Online

Описатель класса хранения в определении функции предоставляет ей класс хранения extern или static .

Синтаксис
function-definition:
declaration-specifiersopt attribute-seqopt declarator declaration-listopt compound-statement
/* attribute-seq поддерживается только компилятором Майкрософт */
declaration-specifiers:
storage-class-specifier declaration-specifiersopt
type-specifier declaration-specifiersopt
type-qualifier declaration-specifiersopt
storage-class-specifier: /* Для определений функции */
extern
static

Если определение функции не содержит storage-class-specifier, по умолчанию устанавливается класс


хранения extern . Функцию можно явно объявить как extern , но это необязательно.

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


связывание, что и любое видимое объявление идентификатора с областью видимости файла. Если
видимого объявления с областью видимости файла нет , идентификатор имеет внешнюю компоновку. Если
идентификатор содержит область видимости файла и не содержит storage-class-specifier, он имеет
внешнюю компоновку. Внешняя компоновка означает , что каждый экземпляр идентификатора определяет
один и тот же объект или функцию. Дополнительные сведения о компоновке и области видимости файла
см. в статье Lifetime, Scope, Visibility, and Linkage (Время существования, область, видимость и компоновка).

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

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

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

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

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

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

См. также
Определения функций в C
Возвращаемый тип
13.10.2020 • 3 minutes to read • Edit Online

Тип возвращаемого значения функции задает размер и тип значения, возвращаемого функцией, и
соответствует спецификатору типа в приведенном ниже синтаксисе.

Синтаксис
function-definition:
declaration-specifiersopt attribute-seqopt declarator declaration-listopt compound-statement
/* attribute-seq поддерживается только компилятором Майкрософт */
declaration-specifiers:
storage-class-specifier declaration-specifiersopt
type-specifier declaration-specifiersopt
type-qualifier declaration-specifiersopt
type-specifier:
void
char
short
int
__int8 /* Только для систем Майкрософт */
__int16 /* Только для систем Майкрософт */
__int32 /* Только для систем Майкрософт */
__int64 /* Только для систем Майкрософт */
long
float
double
signed
unsigned
struct-or-union-specifier
enum-specifier
typedef-name
Компонент type-specifier может задавать любой базовый тип, тип структуры или тип объединения. Если
описатель type-specifier не включен, предполагается возвращаемый тип int .

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


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

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


typedef struct
{
char name[20];
int id;
long class;
} STUDENT;

/* Return type is STUDENT: */

STUDENT sortstu( STUDENT a, STUDENT b )


{
return ( (a.id < b.id) ? a : b );
}

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

NOTE
Эффективность можно увеличить путем передачи указателей на конкретную структуру , а не на всю структуру.

char *smallstr( char s1[], char s2[] )


{
int i;

i = 0;
while ( s1[i] != '\0' && s2[i] != '\0' )
i++;
if ( s1[i] == '\0' )
return ( s1 );
else
return ( s2 );
}

В этом примере определяется функция, возвращающая указатель на массив символов. Функция принимает
в качестве аргументов две строки (два массива) символов и возвращает указатель на более короткую из
них. Указатель на массив указывает на первый из элементов массива и имеет его тип; таким образом,
возвращаемый тип функции — указатель на тип char .

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

См. также
Определения функций в C
Параметры
13.10.2020 • 4 minutes to read • Edit Online

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

Синтаксис
function-definition :
declaration-specifiers необ. attribute-seq необ. declarator declaration-list необ. compound-statement

/* attribute-seq используется только в системах Майкрософт */

declarator :
pointer необ. direct-declarator

direct-declarator : /* Оператор объявления функции */


direct-declarator ( parameter-type-list ) /* Оператор объявления нового стиля */
direct-declarator ( identifier-list необ. ) /* Оператор объявления старого стиля */

parameter-type-list : /* Список параметров */


parameter-list
parameter-list , ...

parameter-list :
parameter-declaration
parameter-list , parameter-declaration

parameter-declaration :
declaration-specifiers declarator
declaration-specifiers abstract-declarator необ.

содержит последовательность объявлений параметров, разделенных запятыми. Форма


parameter-type-list
каждого параметра в списке параметров выглядит следующим образом.

register необ. type-specifier declarator необ.

Параметры функции, объявленные с атрибутом auto , создают ошибки. Идентификаторы параметров


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

Каждому идентификатору в parameter-type-list должен предшествовать соответствующий описатель


типа, как показано в следующем примере:
void new( double x, double y, double z )
{
/* Function body here */
}

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

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

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

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

См. также
Определения функций в C
Текст функции
13.10.2020 • 2 minutes to read • Edit Online

Тело функции — это составной оператор, содержащий операторы, которые определяют выполняемые
функцией действия.

Синтаксис
function-definition:
declaration-specifiersopt attribute-seqopt declarator declaration-listopt compound-statement
/* attribute-seq поддерживается только компилятором Майкрософт */
compound-statement: /* Текст функции */
{ declaration-listopt statement-listopt }
Если не указано иное, переменные, объявленные в теле функции (локальные переменные), имеют класс
хранения auto . При вызове функции создается хранилище для локальных переменных и выполняются
локальные инициализации. Управление передается первому оператору в составном выражении compound-
statement и продолжается до тех пор, пока не будет выполнен оператор return или достигнут конец тела
функции. Затем управление возвращается в точку, из которой вызвана функция.

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

См. также
Определения функций в C
Прототипы функций
13.10.2020 • 5 minutes to read • Edit Online

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

Синтаксис
declaration:
declaration-specifiers attribute-seqopt init-declarator-listopt ;
/* attribute-seqopt поддерживается только компилятором Майкрософт */
declaration-specifiers:
storage-class-specifier declaration-specifiersopt
type-specifier declaration-specifiersopt
type-qualifier declaration-specifiersopt
init-declarator-list:
init-declarator
init-declarator-list , init-declarator
init-declarator:
declarator
declarator = initializer
declarator:
pointeropt direct-declarator
direct-declarator: /* Декларатор функции */
direct-declarator ( parameter-type-list ) /* Декларатор нового стиля */
direct-declarator ( identifier-listopt ) /* Декларатор устаревшего стиля */
Прототип имеет ту же форму, что и определение функции, но завершается точкой с запятой сразу после
закрывающей круглой скобки и поэтому не имеет тела. В любом случае возвращаемый тип должен
соответствовать возвращаемому типу, указанному в определении функции.

Ниже перечислены важные случаи применения прототипов функций:

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

Без полных прототипов выполняются стандартные преобразования, но не производится попытка


сравнения типа или количества аргументов с количеством параметров.

Прототипы используются для инициализации указателей на функции до определения этих функций.

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


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

Преобразованный тип каждого параметра определяет интерпретацию аргументов, помещаемых в стек при
вызове функции. Несоответствие типов аргументов и параметров может приводить к неправильной
интерпретации аргументов в стеке. Например, если на 16-разрядном компьютере в качестве аргумента
передается 16-разрядный указатель, объявленный как параметр long , первые 32 бита в стеке
интерпретируются как параметр типа long . Такая ошибка создает проблемы не только с параметром
long , но и со всеми последующими параметрами. Ошибки такого типа можно обнаруживать, объявляя
полные прототипы для всех функций.

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

Полные объявления параметров ( int a ) могут использоваться совместно с абстрактными операторами


объявления ( int ) в одном объявлении. Например, следующее объявление является допустимым:

int add( int a, int );

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

Теперь область видимости прототипа в компиляторе Microsoft C соответствует стандарту ANSI при
компиляции с параметром /Za . Таким образом, если вы объявите в прототипе тег struct или union , этот
тег добавляется именно в этой области, а не в глобальной области. Например, если выполнять
компиляцию с параметром /Za в соответствии со стандартом ANSI, эту функцию невозможно будет
вызвать без получения ошибки несоответствия типов:

void func1( struct S * );

Чтобы исправить код, определите или объявите struct или union в глобальной области перед
прототипом функции:

struct S;
void func1( struct S * );

При использовании параметра /Ze этот тег будет по-прежнему находиться в глобальной области.

См. также
Функции
Вызовы функций
13.10.2020 • 4 minutes to read • Edit Online

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

expression (expression-listopt)
где expression — это имя функции или выражение, результатом которого является адрес функции, а
expression-list содержит список выражений, разделенных запятыми. Значения этих выражений являются
аргументами, которые передаются функции. Если функция не возвращает значение, при ее объявлении
необходимо указать, что она возвращает void .

Если объявление указывается до вызова функции, однако информация о ее параметрах не приводится, то


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

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

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

Пример
В следующем примере представлен вызов функций, совершаемый из оператора switch :
int main()
{
/* Function prototypes */

long lift( int ), step( int ), drop( int );


void work( int number, long (*function)(int i) );

int select, count;


.
.
.
select = 1;
switch( select )
{
case 1: work( count, lift );
break;

case 2: work( count, step );


break;

case 3: work( count, drop );


/* Fall through to next case */
default:
break;
}
}

/* Function definition */

void work( int number, long (*function)(int i) )


{
int i;
long j;

for ( i = j = 0; i < number; i++ )


j += ( *function )( i );
}

В этом примере вызов функции располагается в функции main :

work( count, lift );

Он передает функции count целочисленную переменную lift , а также адрес функции work . Обратите
внимание, что адрес функции передается просто в виде идентификатора функции, поскольку он равен
выражению указателя. Чтобы идентификатор функции можно было использовать таким образом, функцию
необходимо объявить и определить до того, как будет использован идентификатор; в противном случае
идентификатор не будет распознан. В этом случае прототип функции work задан в начале функции main .

Параметр function в функции work объявлен как указатель на функцию, принимающую один аргумент
типа int и возвращающую значение типа long . Скобки вокруг имени параметра являются
обязательными. Без них это объявление будет означать, что функция возвращает указатель на значение
типа long .

Функция work вызывает выбранную функцию из цикла for , используя следующий вызов:

( *function )( i );

Вызываемой функции передается один аргумент , i :


См. также
Функции
Аргументы
13.10.2020 • 5 minutes to read • Edit Online

Аргументы в вызове функции могут иметь следующую форму:

expression ( expression-listopt ) /* Вызов функции */

При вызове функции параметр expression-list содержит список выражений, разделенных запятыми.
Значения этих выражений являются аргументами, которые передаются функции. Если функция не
принимает аргументы, то список expression-list должен содержать ключевое слово void .

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

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

Порядок вычисления аргументов может различаться в зависимости от конкретного компилятора и уровня


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

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

Количество выражений в expression-list должно совпадать с количеством параметров, если в прототипе


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

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

Пример
В следующем примере в качестве аргументов используются указатели:
int main()
{
/* Function prototype */

void swap( int *num1, int *num2 );


int x, y;
.
.
.
swap( &x, &y ); /* Function call */
}

/* Function definition */

void swap( int *num1, int *num2 )


{
int t;

t = *num1;
*num1 = *num2;
*num2 = t;
}

В этом примере функция swap объявлена внутри функции main . Она имеет два аргумента, num1 и num2 ,
которые являются указателями на значения типа int . Параметры num1 и num2 в определении прототипа
также объявляются как указатели на значения типа int .

Функция вызывается следующей инструкцией:

swap( &x, &y )

Адрес x , который здесь используется, сохраняется в аргументе num1 , а адрес y — в аргументе num2 .
Теперь для одного и того же местоположения имеется два имени, или псевдонима. Ссылки на значения
*num1 и *num2 в функции swap одновременно представляют собой ссылки на значения x и y в функции
main . Присваивания внутри функции swap , по сути, меняют содержимое переменных x и y . Поэтому
оператор return не требуется.

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

См. также
Вызовы функций
Вызовы с переменным количеством аргументов
13.10.2020 • 2 minutes to read • Edit Online

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

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

Все аргументы, заданные в вызове функции, помещаются в стек. Исключение составляют случаи, когда
задано соглашение о вызовах __fastcall . Число параметров, объявленных для функции, определяет ,
сколько аргументов взяты из стека и присвоены параметрам. Ответственность за извлечение любых
дополнительных аргументов из стека и за определение числа присутствующих аргументов лежит на
пользователе. Файл STDARG.H содержит макросы в стиле ANSI для доступа к аргументам функций,
принимающих переменное число аргументов. Кроме того, до сих пор поддерживаются макросы в стиле
XENIX из файла VARARGS.H.
Ниже приводится пример объявления функции, вызывающей переменное число аргументов.

int average( int first, ...);

См. также
Вызовы функций
Рекурсивные функции
13.10.2020 • 2 minutes to read • Edit Online

Любая функция в программе на языке C может вызываться рекурсивно, т. е. может вызывать сама себя.
Число рекурсивных вызовов ограничено размером стека. Сведения о параметрах компоновщика,
определяющих размер стека, см. в описании параметра компоновщика /STACK (распределения стека). При
каждом вызове функции для параметров и переменных auto и register выделяется новая память, чтобы не
перезаписывались их значения в предыдущих (незаконченных) вызовах. Параметры доступны
непосредственно только экземпляру функции, в котором они были созданы. Последующим экземплярам
функции предыдущие параметры непосредственно недоступны.

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

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

int factorial( int num ); /* Function prototype */

int main()
{
int result, number;
.
.
.
result = factorial( number );
}

int factorial( int num ) /* Function definition */


{
.
.
.
if ( ( num > 0 ) || ( num <= 10 ) )
return( num * factorial( num - 1 ) );
}

См. также
Вызовы функций
Краткие сведения о синтаксисе языка C
07.05.2020 • 2 minutes to read • Edit Online

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

NOTE
Приведенная здесь краткая информация о синтаксисе не относятся к стандарту ANSI C; она приводится
исключительно в информационных целях. Синтаксис для систем Microsoft описывается в комментариях ,
которые приводятся после синтаксиса.

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

Терминальные слова — это конечные точки в определении синтаксиса. Никакое другое разрешение
невозможно. Терминальные слова включают в себя набор зарезервированных ключевых слов и
определенные пользователем идентификаторы.

Нетерминальные символы представляют собой местозаполнители в синтаксисе и определяются в другом


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

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


объекту директива

{ expressionopt }

указывает необязательное выражение, заключенное в фигурные скобки.

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


синтаксиса. Ниже перечислены символы и шрифты.

АТРИБУТ ОПИСАНИЕ

нетерминальный Курсивом выделяются нетерминальные символы.

const Терминальные символы, выделенные жирным шрифтом,


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

opt Нетерминальные символы, за которыми следует атрибут


o p t , всегда являются необязательными.

Шрифт по умолчанию Символы в наборе, описанные или перечисленные в этом


шрифте, можно использовать в качестве терминальных
символов в операторах языка C.

Двоеточие ( : ) после нетерминального элемента обозначает начало его определения. Альтернативные


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

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

Лексемы

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

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

Константы

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

Инструкции

Символы пунктуации

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

token:
keyword
identifier
constant
string-literal
operator
punctuator
preprocessing-token:
header-name
identifier
pp-number
character-constant
string-literal
operator punctuator
любой символ, отличный от пробела, который не может быть одним и перечисленных выше элементов

header-name:
< path-spec >
" path spec "
path-spec:
Допустимый путь к файлу

pp-number:
digit
. digit
pp-number digit
pp-number nondigit
pp-number e sign
pp-number E sign
pp-number .

См. также
Лексическая грамматика
Общие сведения о ключевых словах
13.10.2020 • 2 minutes to read • Edit Online

keyword: одно из нижеперечисленного


auto
double
int
struct
break
else
long
switch

case
enum
register
typedef
char
extern
return
union

const
float
short
unsigned
continue
for
signed
void

default
goto
sizeof
volatile
do
if
static
while

См. также
Лексическая грамматика
Общие сведения об идентификаторах
15.05.2020 • 2 minutes to read • Edit Online

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

См. также
Лексическая грамматика
Общие сведения о константах
15.05.2020 • 2 minutes to read • Edit Online

constant:
floating-point-constant
integer-constant
enumeration-constant
character-constant
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
integer-constant:
decimal-constant integer-suffixopt
binary-constant integer-suffixopt
octal-constant integer-suffixopt
hexadecimal-constant integer-suffixopt
decimal-constant:
nonzero-digit
decimal-constant digit
binary-constant:
0b binary-digit
0B binary-digit
octal-constant:
0
octal-constant octal-digit
hexadecimal-constant:
0x hexadecimal-digit
0X hexadecimal-digit
hexadecimal-constant hexadecimal-digit
nonzero-digit: одна из указанных ниже
123456789
octal-digit: одна из указанных ниже
01234567
hexadecimal-digit: одна из указанных ниже
0123456789
abcdef
ABCDEF
unsigned-suffix: one of
uU
long-suffix: one of
lL
character-constant:
' c-char-sequence '
L' c-char-sequence '
integer-suffix:
unsigned-suffix long-suffixopt
long-suffix unsigned-suffixopt
c-char-sequence:
c-char
c-char-sequence c-char
c-char:
Любой член исходной кодировки, кроме escape-последовательности одинарной кавычки ( ' ), обратной
косой черты ( \ ) или символа новой строки

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

См. также
Лексическая грамматика
Общие сведения о строковых литералах
15.05.2020 • 2 minutes to read • Edit Online

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

См. также
Лексическая грамматика
Операторы (C)
13.10.2020 • 2 minutes to read • Edit Online

operator — один из следующих вариантов:


[] () . -> ++ -- & * + - ~ ! sizeof / % << >> <> <= >= == != ^ | && !!? := *= /= %= += -= <<= >>=
&= ^= |= , # ##
assignment-operator: один из следующих операторов:
= *= /= %= += -= <<= >>= &= ^= |=

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

Символ пунктуации — один из следующих:


[](){}*,:=;.#

См. также
Лексическая грамматика
Грамматика структуры фразы
07.05.2020 • 2 minutes to read • Edit Online

Выражения

Объявления

Операторы

Внешние определения

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

primary-expression:
identifier
constant
string-literal
( expression )
expression:
assignment-expression
expression , assignment-expression
constant-expression:
conditional-expression
conditional-expression:
logical-OR-expression
logical-OR-expression ? expression : conditional-expression
assignment-expression:
conditional-expression
unary-expression assignment-operator assignment-expression
postfix-expression:
primary-expression
postfix-expression [ expression ]
postfix-expression ( argument-expression-listopt )
postfix-expression . identifier
postfix-expression -> identifier
postfix-expression ++
postfix-expression --
argument-expression-list:
assignment-expression
argument-expression-list , assignment-expression
unary-expression:
postfix-expression
++ unary-expression
-- unary-expression
unary-operator
cast-expression
sizeof unary-expression
sizeof ( type-name )
unary-operator: one of
&*+-~!
cast-expression:
unary-expression
( type-name ) cast-expression
multiplicative-expression:
cast-expression
multiplicative-expression * cast-expression
multiplicative-expression / cast-expression
multiplicative-expression % cast-expression
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
shift-expression:
additive-expression
shift-expression << additive-expression
* shift-expression* >> additive-expression
relational-expression:
shift-expression
relational-expression < shift-expression
* relational-expression* > shift-expression
* relational-expression* <= shift-expression
* relational-expression* >= shift-expression
equality-expression:
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression
AND-expression:
equality-expression
AND-expression & equality-expression
exclusive-OR-expression:
AND-expression
exclusive-OR-expression ^ AND-expression
inclusive-OR-expression:
exclusive-OR-expression
inclusive-OR-expression | exclusive-OR-expression
logical-AND-expression:
inclusive-OR-expression
logical-AND-expression && inclusive-OR-expression
logical-OR-expression:
logical-AND-expression
logical-OR-expression || logical-AND-expression

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

declaration :
declaration-specifiers attribute-seq необ. init-declarator-list необ. ;

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

attribute-seq : /* Только для систем Майкрософт */


attribute attribute-seq необ.

attribute : один из /* Только для систем Майкрософт */


__asm __clrcall __stdcall __based __fastcall __thiscall __cdecl __inline __vectorcall

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

init-declarator :
declarator
declarator = initializer /* Для инициализации скалярных типов */
storage-class-specifier :
auto
register
static
extern
typedef
__declspec ( extended-decl-modifier-seq ) /* Только для систем Майкрософт */
type-specifier :
void
char
short
int
__int8 /* Только для систем Майкрософт */
__int16 /* Только для систем Майкрософт */
__int32 /* Только для систем Майкрософт */
__int64 /* Только для систем Майкрософт */
long
float
double
signed
unsigned
struct-or-union-specifier
enum-specifier
typedef-name
type-qualifier :
const
volatile

declarator :
pointer необ. direct-declarator

direct-declarator :
identifier
( declarator )
direct-declarator [ constant-expression необ. ]
direct-declarator ( parameter-type-list ) /* Оператор объявления нового стиля */
direct-declarator ( identifier-list необ. ) /* Оператор объявления старого стиля */

pointer :
* type-qualifier-list необ.
* type-qualifier-list необ. pointer

parameter-type-list : /* Список параметров */


parameter-list
parameter-list , ...

parameter-list :
parameter-declaration
parameter-list , parameter-declaration

type-qualifier-list :
type-qualifier
type-qualifier-list type-qualifier

enum-specifier :
enum identifier необ. { enumerator-list }
enum identifier

enumerator-list :
enumerator
enumerator-list , enumerator

enumerator :
enumeration-constant
enumeration-constant = constant-expression

enumeration-constant :
identifier

struct-or-union-specifier :
struct-or-union identifier необ. { struct-declaration-list }
struct-or-union identifier

struct-or-union :
struct
union

struct-declaration-list :
struct-declaration
struct-declaration-list struct-declaration
struct-declaration :
specifier-qualifier-list struct-declarator-list ;

specifier-qualifier-list :
type-specifier specifier-qualifier-list необ.
type-qualifier specifier-qualifier-list необ.

struct-declarator-list :
struct-declarator struct-declarator-list , struct-declarator

struct-declarator :
declarator
type-specifier declarator необ. : constant-expression

parameter-declaration :
declaration-specifiers declarator /* Именованный оператор объявления */
declaration-specifiers abstract-declarator необ. /* Анонимный оператор объявления */

identifier-list : /* Для оператора объявления старого стиля */


identifier
identifier-list , identifier

abstract-declarator : /* Используется с анонимными операторами объявления */


pointer
pointer необ. direct-abstract-declarator

direct-abstract-declarator :
( abstract-declarator )
direct-abstract-declarator необ. [ constant-expression необ. ]
direct-abstract-declarator необ. ( parameter-type-list необ. )

initializer :
assignment-expression
{ initializer-list } /* Для агрегатной инициализации */
{ initializer-list , }

initializer-list :
initializer
initializer-list , initializer

type-name :
specifier-qualifier-list abstract-declarator необ.

typedef-name :
identifier

extended-decl-modifier-seq : /* Только для систем Майкрософт */


extended-decl-modifier необ.
extended-decl-modifier-seq extended-decl-modifier

extended-decl-modifier : /* Только для систем Майкрософт */


thread
naked
dllimport
dllexport
См. также
Соглашения о вызовах
Грамматика структуры фразы
Устаревшие соглашения о вызовах
Сводка по операторам C
13.10.2020 • 2 minutes to read • Edit Online

statement :
  labeled-statement
  compound-statement
  expression-statement
  selection-statement
  iteration-statement
  jump-statement
  try-except-statement /* Только для систем Майкрософт */
  try-finally-statement /* Только для систем Майкрософт */

jump-statement :
  goto identifier ;
  continue ;
  break ;
  return expression необ. ;
  __leave ; /* Только для систем Майкрософт 1 */
compound-statement :
  { declaration-list необ. statement-list необ. }

declaration-list :
  declaration
  declaration-list declaration

statement-list :
  statement
  statement-list statement

expression-statement :
  expression необ. ;

iteration-statement :
  while ( expression ) statement
  do statement while ( expression ) ;
  for ( expression необ. ; expression необ. ; expression необ. ) statement

selection-statement :
  if ( expression ) statement
  if ( expression ) statement else statement
  switch ( expression ) statement

labeled-statement :
  identifier : statement
  case constant-expression : statement
  default : statement

try-except-statement : /* Только для систем Майкрософт */


  __try compound-statement __except ( expression ) compound-statement
try-finally-statement : /* Только для систем Майкрософт */
  __try compound-statement __finally compound-statement

1 Ключевое слово __leave допустимо только в блоке __try try-except-statement или try-finally-statement
.

См. также раздел


Грамматика структуры фразы
Внешние определения
15.05.2020 • 2 minutes to read • Edit Online

translation-unit:
external-declaration
translation-unit external-declaration
external-declaration: /* Допускается только в области видимости файла (внешней) */
function-definition
declaration
function-definition: /*Здесь декларатор является декларатором функции */
declaration-specifiersopt declarator declaration-listopt compound-statement

См. также
Грамматика структуры фразы
Поведение, определяемое реализацией
07.05.2020 • 2 minutes to read • Edit Online

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

Порядок изложения в этом разделе соответствует порядку изложения в соответствующем разделе


стандарта ANSI. Каждый описываемый элемент содержит ссылки на стандарт ANSI, в котором поясняется
поведение, определяемое реализацией.

NOTE
В этом разделе описывается только версия компилятора C для американского варианта английского языка.
Реализации Microsoft C для других языков могут немного отличаться.

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

ANSI 2.1.1.3 Определение диагностики


Microsoft C создает сообщения об ошибках в следующем виде:

filename ( line-number ) : diagnostic C number message

Где filename обозначает имя исходного файла, в котором была обнаружена ошибка; line-number — номер
строки, в которой компилятор обнаружил ошибку; diagnostic имеет значение "error" (ошибка) или "warning"
(предупреждение); number — уникальное четырехзначное число, определяющее ошибку или
предупреждение (с предшествующим символом C , как указано в синтаксисе); а message — поясняющее
сообщение.

См. также
Поведение, определяемое реализацией
Среда
07.05.2020 • 2 minutes to read • Edit Online

Аргументы функции main

Интерактивные устройства

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

ANSI 2.1.2.2.1 Семантика аргументов функции main


В языке Microsoft C функция, вызываемая при запуске программы, называется main . Для функции main не
существует объявляемого прототипа и она может быть определена с двумя, тремя параметрами или без
параметров.

int main( void )


int main( int argc, char *argv[] )
int main( int argc, char *argv[], char *envp[] )

Третья строка приведенного выше примера, где функция main принимает три параметра, представляет
собой расширение Майкрософт для стандарта ANSI C. Третий параметр (envp ) — это массив указателей на
переменные среды. Массив envp завершается пустым указателем. Дополнительные сведения о функции
main и параметре envp см. в статье main Function and Program Execution (Функция main и выполнение
программы).

Переменная argc никогда не принимает отрицательное значение.

Массив строк заканчивается переменной argv[argc] , содержащей пустой указатель.

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

Программа, вызванная без аргументов командной строки, будет получать для переменной argc значение 1,
так как имя исполняемого файла размещается в переменной argv[0] . (В версиях MS-DOS до 3.0 имя
исполняемого файла недоступно. В переменной argv[0] размещается буква "C"). Строки, на которые
указывают переменные от argv[1] до argv[argc – 1] , представляют параметры программы.

Параметры argc и argv можно изменять. При этом они сохраняют свои последние значения от момента
запуска до завершения программы.

См. также
Среда
Интерактивные устройства
06.05.2020 • 2 minutes to read • Edit Online

ANSI 2.1.2.3 Описание интерактивного устройства


Microsoft C определяет клавиатуру и дисплей как интерактивные устройства.

См. также
Среда
Поведение идентификаторов
13.10.2020 • 2 minutes to read • Edit Online

Значимые символы без внешней компоновки

Значимые символы с внешней компоновкой

Верхний и нижний регистр

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

ANSI 3.1.2 Число значимых символов без внешней компоновки


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

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

ANSI 3.1.2 Число значимых символов при использовании внешней компоновки


Идентификаторы, объявленные extern в программах, которые скомпилированы с использованием языка
Microsoft C, являются значимыми до 247 символов. Это значение по умолчанию можно изменить на
меньшее число, воспользовавшись параметром /H (ограничивает длину внешних имен).

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

ANSI 3.1.2 Учитываются ли различия в регистре символов


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

См. также
Поведение идентификаторов
Знаки
07.05.2020 • 2 minutes to read • Edit Online

Набор символов ASCII

Многобайтовая кодировка

Число битов на символ

Кодировки

Непредставимые символьные константы

Расширенные символы

Преобразование многобайтовых символов

Диапазон значений char

См. также
Поведение, определяемое реализацией
Набор символов ASCII
07.05.2020 • 2 minutes to read • Edit Online

ANSI 2.2.1 Члены исходной кодировки и кодировки выполнения


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

NOTE
Внимание! Поскольку драйверы клавиатуры и консоли могут менять сопоставление кодировки, в программах для
международного распространения необходимо проверять код страны/региона.

См. также
Символы
Многобайтовые символы
07.05.2020 • 2 minutes to read • Edit Online

ANSI 2.2.1.2 Состояния сдвига для многобайтовых символов


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

См. также
Символы
Число битов на символ
07.05.2020 • 2 minutes to read • Edit Online

ANSI 2.2.4.2.1 Число битов в символе


Количество битов в символе определяется константой манифеста CHAR_BIT . В файле LIMITS.H для
константы CHAR_BIT задано значение 8.

См. также
Символы
Кодировки
07.05.2020 • 2 minutes to read • Edit Online

ANSI 3.1.3.4 Сопоставление членов кодировки исходного кода


Исходная кодировка и кодировка выполнения содержат символы ASCII, перечисленные в следующей
таблице. В таблице также приведены escape-последовательности.

Escape-последовательность
ESC A P E- ПОСЛЕДОВАТЕЛЬНОСТЬ ЗНАК ЗНАЧЕНИЕ A SC II

\a Предупреждение/звонок 7

\b Backspace 8

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

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

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

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

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

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

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

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

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

ANSI 3.1.3.4 Значение целочисленной символьной константы, которая содержит символ или escape-
последовательность, не представленную в базовой кодировке выполнения или в расширенной кодировке
для расширенной символьной константы

Все символьные константы или escape-последовательности можно представить в виде расширенной


кодировки.

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

ANSI 3.1.3.4 Значение целочисленной символьной константы, которая содержит более одного символа,
или расширенной символьной константы, которая содержит более одного многобайтового символа

Обычная символьная константа, ab, имеет целочисленное значение (int)0x6162. Если размер составляет
более одного байта, то ранее считанные байты сдвигаются влево на значение CHAR_BIT , а следующий байт
сравнивается (при помощи оператора побитового ИЛИ) с младшими битами значения CHAR_BIT . Число
байтов в многобайтовой символьной константе не может превышать (int) — 4 байта в коде для 32-
разрядной системы.

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


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

См. также
Символы
Преобразование многобайтовых символов
07.05.2020 • 2 minutes to read • Edit Online

ANSI 3.1.3.4 Текущий языковой стандарт , используемый для преобразования многобайтовых символов в
соответствующие расширенные символы (коды) для расширенной символьной константы

Текущий языковой стандарт — это языковой стандарт C по умолчанию. Его можно изменить с помощью
директивы #pragma setlocale.

См. также
Символы
Диапазон значений типа char
13.10.2020 • 2 minutes to read • Edit Online

ANSI 3.2.1.1 Имеет ли "простой" тип char тот же диапазон значений, что и signed char или unsigned char

Все знаковые значения char находятся в диапазоне от –128 до 127. Все беззнаковые значения char находятся
в диапазоне от 0 до 255.

Параметр компилятора /J указывает , что для char по умолчанию вместо signed char будет
использоваться unsigned char .

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

Диапазон целочисленных значений

Понижение уровня целых чисел

Поразрядные операции со знаком

Остатки от деления

Сдвиги вправо

См. также
Поведение, определяемое реализацией
Диапазон целочисленных значений
13.10.2020 • 2 minutes to read • Edit Online

ANSI 3.1.2.5 Представления и наборы значений различных целочисленных типов данных


Целочисленные типы данных содержат 32 бита (4 байта). Знаковые целочисленные типы представлены в
форме дополнительного кода. В старшем бите содержится следующий знак: 1 означает отрицательные
числа, 0 — положительные числа и ноль. Значения перечислены ниже:

TYPE МИНИМАЛЬНОЕ И МАКСИМАЛЬНОЕ ЗНАЧЕНИЕ

unsigned short От 0 до 65535

signed short От -32768 до 32767

unsigned long От 0 до 4294967295

signed long От -2147483648 до 2147483647

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

ANSI 3.2.1.2 Результат преобразования целого числа в более короткое целое число со знаком или
результат преобразования целого числа без знака в целое число со знаком той же длины, если
представление значения невозможно.

Когда целое число типа long приводится к типу short или тип short приводится к типу char , младшие
байты сохраняются.

Например, строкой

short x = (short)0x12345678L;

переменной x присваивается значение 0x5678, а строкой

char y = (char)0x1234;

переменной y присваивается значение 0x34.

При преобразовании переменных signed в переменные unsigned и наоборот битовые шаблоны не


изменяются. Например, при приведении значения -2 (0xFE) к значению unsigned получается значение 254
(также 0xFE).

См. также
Целые числа
Битовые операции со знаком
07.05.2020 • 2 minutes to read • Edit Online

ANSI 3.3 Результаты выполнения побитовых операций над знаковыми целочисленными значениями
Побитовые операции над знаковыми целочисленными значениями работают так же, как и над
беззнаковыми. Например, значение -16 & 99 можно представить в двоичном виде следующим образом:

11111111 11110000
& 00000000 01100011
_________________
00000000 01100000

Результат выполнения побитовой операции И будет равен 96.

См. также
Целые числа
Остатки от деления
07.05.2020 • 2 minutes to read • Edit Online

ANSI 3.3.5 Знак остатка при целочисленном делении


Знак остатка совпадает со знаком делимого. Например, примененная к объекту директива

50 / -6 == -8
50 % -6 == 2
-50 / 6 == -8
-50 % 6 == -2

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

Результат сдвига вправо отрицательного целого типа со знаком

Сдвиг вправо отрицательного значения соответствует делению абсолютного значения на два с


округлением вниз. Например, значение signed short , равное –253 (шестнадцатеричное 0xFF03, двоичное
11111111 00000011), сдвинутое вправо на один бит , дает значение –127 (шестнадцатеричное 0xFF81,
двоичное 11111111 10000001). Положительное значение 253, сдвинутое вправо, дает значение +126.

При сдвиге вправо бит знака целочисленных типов со знаком сохраняется. При сдвиге вправо целого числа
со знаком старший значащий бит остается установленным. Например, если число 0xF0000000 имеет тип
int со знаком, то при сдвиге вправо мы получим число 0xF8000000. Если 32 раза выполнить сдвиг вправо
отрицательного int , в результате получится число 0xFFFFFFFF.

При сдвиге вправо целого числа без знака старший значащий бит очищается. Например, если число 0xF000
не имеет знака, в результате получается 0x7800. При сдвиге 32 раза unsigned или положительного числа
int вправо получится число 0x00000000.

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

Значения

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

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

См. также
Поведение, определяемое реализацией
Значения
13.10.2020 • 2 minutes to read • Edit Online

ANSI 3.1.2.5 Представления и наборы значений различных типов чисел с плавающей запятой
Тип floatпредставлен 32 битами: 1 для знака, 8 для экспоненты и 23 для мантиссы. Он имеет диапазон
+/–3,4E38 с точностью не менее 7 знаков.
Тип double представлен 64 битами: 1 для знака, 11 для экспоненты и 52 для мантиссы. Он имеет диапазон
+/–1,7E308 с точностью не менее 15 знаков.
Тип long double отличается, но имеет такое же представление, как и тип double в компиляторе C
Майкрософт.

См. также
Вычисления с плавающей запятой
Приведение целочисленных значений к значениям
с плавающей запятой
13.10.2020 • 2 minutes to read • Edit Online

ANSI 3.2.1.3 Направление усечения при преобразовании целого числа в число с плавающей запятой,
которое не может точно представить исходное значение

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

Например, приведение числа типа unsigned long (точность — 32 бита) к типу float (мантисса которого
имеет точность 23 бита) приводит к округлению числа до ближайшего кратного 256. Значения long в
диапазоне от 4 294 966 913 до 4 294 967 167 округляются до значения 4 294 967 040 с типом float .

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

ANSI 3.2.1.4 Направление усечения или округления при преобразовании числа с плавающей запятой в
формат с плавающей запятой меньшего размера

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

См. также
Вычисления с плавающей запятой
Массивы и указатели
07.05.2020 • 2 minutes to read • Edit Online

Максимальный размер массива

Вычитание указателей

См. также
Поведение, определяемое реализацией
Максимальный размер массива
13.10.2020 • 2 minutes to read • Edit Online

ANSI 3.3.3.4, 4.1.1 Тип целочисленного значения, необходимый для хранения массива максимального
размера, — т. е. размер значения size_t

Определение типа typedef для типа size_t на 32-разрядных платформах (x86): unsigned int . Определение
типа (typedef) для size_t на 64-разрядных платформах: unsigned __int64 .

См. также
Массивы и указатели
Вычитание указателей
13.10.2020 • 2 minutes to read • Edit Online

ANSI 3.3.6, 4.1.1 Тип целого числа, необходимый для сохранения различия между двумя указателями на
элементы одного массива, ptrdiff_t

Определение типа typedef для типа ptrdiff_t на 32-разрядных платформах (x86): int . Определение типа
(typedef) для ptrdiff_t на 64-разрядных платформах: __int64 .

См. также
Массивы и указатели
Регистры: доступность регистров
07.05.2020 • 2 minutes to read • Edit Online

ANSI 3.5.1 . В какой степени можно управлять фактическим размещением объектов в регистрах при помощи
описателя класса регистрового хранения

Компилятор не учитывает пользовательские запросы на регистровые переменные. При оптимизации


компилятор принимает решения самостоятельно.

См. также
Поведение, определяемое реализацией
Структуры, объединения, перечисления и битовые
поля
06.05.2020 • 2 minutes to read • Edit Online

Неправильный доступ к объединению

Заполнение и выравнивание членов структуры

Знак битовых полей

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

Тип перечисления

См. также
Поведение, определяемое реализацией
Неправильный доступ к объединению
13.10.2020 • 2 minutes to read • Edit Online

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

Например, объявлено объединение float и int . Сохраняется значение float , но программа позднее
и