~~~~~~~~~~~~~~~~~~~~ Arc.Ask3.Ru ~~~~~~~~~~~~~~~~~~~~~ 
Номер скриншота №:
✰ BD6905F5CE66F4EB2305FDDD5A689F1E__1717443300 ✰
Заголовок документа оригинал.:
✰ C syntax - Wikipedia ✰
Заголовок документа перевод.:
✰ Синтаксис C — Википедия ✰
Снимок документа находящегося по адресу (URL):
✰ https://en.wikipedia.org/wiki/C_syntax ✰
Адрес хранения снимка оригинал (URL):
✰ https://arc.ask3.ru/arc/aa/bd/1e/bd6905f5ce66f4eb2305fddd5a689f1e.html ✰
Адрес хранения снимка перевод (URL):
✰ https://arc.ask3.ru/arc/aa/bd/1e/bd6905f5ce66f4eb2305fddd5a689f1e__translat.html ✰
Дата и время сохранения документа:
✰ 21.06.2024 10:32:28 (GMT+3, MSK) ✰
Дата и время изменения документа (по данным источника):
✰ 3 June 2024, at 22:35 (UTC). ✰ 

~~~~~~~~~~~~~~~~~~~~~~ Ask3.Ru ~~~~~~~~~~~~~~~~~~~~~~ 
Сервисы Ask3.ru: 
 Архив документов (Снимки документов, в формате HTML, PDF, PNG - подписанные ЭЦП, доказывающие существование документа в момент подписи. Перевод сохраненных документов на русский язык.)https://arc.ask3.ruОтветы на вопросы (Сервис ответов на вопросы, в основном, научной направленности)https://ask3.ru/answer2questionТоварный сопоставитель (Сервис сравнения и выбора товаров) ✰✰
✰ https://ask3.ru/product2collationПартнерыhttps://comrades.ask3.ru


Совет. Чтобы искать на странице, нажмите Ctrl+F или ⌘-F (для MacOS) и введите запрос в поле поиска.
Arc.Ask3.ru: далее начало оригинального документа

Синтаксис C — Википедия Jump to content

Синтаксис Си

Из Википедии, бесплатной энциклопедии
Фрагмент кода C , который печатает «Hello, World!»

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

C Синтаксис использует принцип максимального Мунка .

Структуры данных [ править ]

Примитивные типы данных [ править ]

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

Все целочисленные типы C имеют signed и unsignedварианты. Если signed или unsigned в большинстве случаев не указывается явно, signedпредполагается. Однако по историческим причинам, просто char это тип, отличный от обоих signed char и unsigned char. Это может быть знаковый или беззнаковый тип, в зависимости от компилятора и набора символов (C гарантирует, что члены базового набора символов C имеют положительные значения). Кроме того, типы битовых полей , указанные как простые int может быть подписанным или беззнаковым, в зависимости от компилятора.

Целочисленные типы [ править ]

Целочисленные типы C имеют разные фиксированные размеры и способны представлять различные диапазоны чисел. Тип charзанимает ровно один байт (наименьшая адресуемая единица хранения), ширина которого обычно составляет 8 бит. (Хотя char может представлять любой из «базовых» символов C, для международных наборов символов может потребоваться более широкий тип.) Большинство целочисленных типов имеют как знаковые, так и беззнаковые разновидности, обозначаемые signed и unsignedключевые слова. Целочисленные типы со знаком могут использовать представление с дополнением до двух , дополнением до единиц или по знаку и величине представлением . Во многих случаях существует несколько эквивалентных способов обозначения типа; например, signed short int и short являются синонимами.

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

Спецификации стандартных целочисленных типов
Кратчайшая форма спецификатора Минимальная ширина (биты)
_Bool 1
char 8
signed char 8
unsigned char 8
short 16
unsigned short 16
int 16
unsigned int 16
long 32
unsigned long 32
long long[примечание 1] 64
unsigned long long[примечание 1] 64

The char тип отличается от обоих signed char и unsigned char, но гарантированно будет иметь то же представление, что и один из них. _Bool и long longтипы стандартизированы с 1999 года и могут не поддерживаться старыми компиляторами C. Тип _Bool обычно доступ осуществляется через typedef имя bool определяется стандартным заголовком stdbool.h.

В общем, ширина и схема представления, реализованные для любой конкретной платформы, выбираются на основе архитектуры машины, при этом некоторое внимание уделяется простоте импорта исходного кода, разработанного для других платформ. Ширина intтип особенно сильно различается в разных реализациях C; он часто соответствует наиболее «естественному» размеру слова для конкретной платформы. Стандартный заголовок limit.h определяет макросы для минимальных и максимальных представимых значений стандартных целочисленных типов, реализованных на любой конкретной платформе.

Помимо стандартных целочисленных типов, могут существовать и другие «расширенные» целочисленные типы, которые можно использовать для typedefs в стандартных заголовках. Для более точного указания ширины программисты могут и должны использовать typedefs из стандартного заголовка stdint.h .

Целочисленные константы могут быть указаны в исходном коде несколькими способами. Числовые значения могут быть указаны в десятичном формате (пример: 1022), восьмеричный с нулем ( 0) в качестве префикса ( 01776) или шестнадцатеричное с 0x (ноль x) в качестве префикса ( 0x3FE). Символ в одинарных кавычках (пример: 'R'), называемая «символьной константой», представляет значение этого символа в наборе символов выполнения с типом int. За исключением символьных констант, тип целочисленной константы определяется шириной, необходимой для представления указанного значения, но всегда не менее ширины, чем int. Это можно переопределить, добавив явный модификатор длины и/или подписи; например, 12lu имеет тип unsigned long. Не существует отрицательных целочисленных констант, но тот же эффект часто можно получить, используя унарный оператор отрицания " -".

Перечисляемый тип [ править ]

Перечисляемый тип в C, указанный с помощью enumКлючевое слово, часто называемое просто «перечислением» (обычно произносится / ˈ n ʌ m / EE -num или / ˈ n m / EE -noom ), представляет собой тип, предназначенный для представления значений в серии именованных констант. Каждая из перечисленных констант имеет тип int. Каждый enum сам тип совместим с char или целочисленный тип со знаком или без знака, но каждая реализация определяет свои собственные правила выбора типа.

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

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

перечисление   цветов   {   КРАСНЫЙ  ,   ЗЕЛЕНЫЙ  ,   СИНИЙ   =   5  ,   ЖЕЛТЫЙ   }   краска_цвет  ; 

Это заявляет о enum colorsтип; тот int константы RED (значение которого равно 0), GREEN (чье значение на единицу больше, чем RED, 1), BLUE (чье значение равно заданному значению 5) и YELLOW (чье значение на единицу больше, чем BLUE, 6); и enum colors переменная paint_color. Константы могут использоваться вне контекста enum (где допускается любое целочисленное значение), а значения, отличные от констант, могут быть присвоены paint_colorили любая другая переменная типа enum colors.

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

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

Типы с плавающей запятой
Спецификаторы типа Точность (десятичные цифры) Диапазон экспоненты
Минимум ИЭЭЭ 754 Минимум ИЭЭЭ 754
float 6 7,2 (24 бита) ±37 ±38 (8 бит)
double 10 15,9 (53 бита) ±37 ±307 (11 бит)
long double 10 34,0 (113 бит) ±37 ±4931 (15 бит)

Константы с плавающей запятой могут быть записаны в десятичной записи , например 1.23. Десятичную экспоненциальную запись можно использовать, добавив e или E за которым следует десятичный показатель степени, также известный как обозначение E , например 1.23e2 (что имеет значение 1,23 × 10 2 = 123,0). Требуется либо десятичная точка, либо показатель степени (в противном случае число анализируется как целочисленная константа). Шестнадцатеричные константы с плавающей запятой подчиняются аналогичным правилам, за исключением того, что перед ними должен стоять префикс 0x и использовать p или P чтобы указать двоичную экспоненту, например 0xAp-2 (что имеет значение 2,5, поскольку A h × 2 −2 = 10 × 2 −2 = 10 ÷ 4). Как десятичные, так и шестнадцатеричные константы с плавающей запятой могут иметь суффикс f или F для обозначения константы типа float, к l (письмо l) или L указать тип long doubleили оставить без суффикса для double постоянный.

Стандартный заголовочный файл float.h определяет минимальные и максимальные значения типов с плавающей запятой реализации float, double, и long double. Он также определяет другие ограничения, относящиеся к обработке чисел с плавающей запятой.

Спецификаторы класса хранилища [ править ]

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

Классы хранения
Спецификаторы Продолжительность жизни Объем Инициализатор по умолчанию
auto Блок (стек) Блокировать Неинициализированный
register Блок (стек или регистр ЦП) Блокировать Неинициализированный
static Программа Блок или единица компиляции Нуль
extern Программа Глобальный (вся программа) Нуль
_Thread_local Нить
(никто) 1 Динамический (куча) Неинициализированный (инициализируется 0 если использовать calloc())
1 Выделяется и освобождается с помощью malloc() и free() библиотечные функции.

Переменные, объявленные внутри блока, по умолчанию имеют автоматическое сохранение, как и переменные, явно объявленные с помощью auto[заметка 2] или registerспецификаторы класса хранилища. auto и registerспецификаторы могут использоваться только внутри функций и объявлений аргументов функций; как таковой, autoспецификатор всегда избыточен. Объекты, объявленные вне всех блоков, а также объекты, объявленные явно с помощью staticСпецификатор класса хранения имеет статическую продолжительность хранения. Статические переменные по умолчанию инициализируются компилятором нулем .

Объекты с автоматическим сохранением являются локальными для блока, в котором они были объявлены, и удаляются при выходе из блока. Кроме того, объекты, объявленные с помощью registerклассу хранения может быть присвоен более высокий приоритет компилятором для доступа к регистрам ; хотя компилятор может отказаться от фактического сохранения каких-либо из них в регистре. Объекты с этим классом хранения нельзя использовать с адресом ( &) унарный оператор. Объекты со статическим хранилищем сохраняются на протяжении всего времени работы программы. Таким образом, к одному и тому же объекту функция может получить доступ через несколько вызовов. Объекты с выделенным сроком хранения создаются и уничтожаются явно с помощью malloc, freeи связанные с ним функции.

The externСпецификатор класса хранилища указывает, что хранилище для объекта было определено в другом месте. При использовании внутри блока это указывает на то, что хранилище было определено объявлением вне этого блока. При использовании вне всех блоков это указывает на то, что хранилище было определено вне модуля компиляции. externСпецификатор класса хранения является избыточным при использовании в объявлении функции. Это указывает на то, что объявленная функция была определена вне модуля компиляции.

The _Thread_local ( thread_local в C++ , начиная с C23 , и в более ранних версиях C, если заголовок <threads.h>включен) спецификатор класса хранения, представленный в C11 , используется для объявления локальной переменной потока. Его можно комбинировать с static или extern чтобы определить связь.

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

Спецификаторы типа [ править ]

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

Неполные типы [ править ]

Неполный тип — это тип структуры или объединения , члены которого еще не указаны, тип массива, размерность которого еще не указана. тип массива , размерность которого еще не указана, или void введите voidтип не может быть завершен). Такой тип не может быть создан (его размер неизвестен) и к его членам нельзя получить доступ (они тоже неизвестны); однако производный тип указателя может использоваться (но не разыменовываться).

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

структура   вещь   *  pt  ; 

Это заявляет pt как указатель на struct thing и неполный тип struct thing. Указатели на данные всегда имеют одинаковую ширину в байтах, независимо от того, на что они указывают, поэтому это утверждение допустимо само по себе (пока ptне разыменовывается). Неполный тип можно дополнить позже в той же области, переобъявив его:

структура   вещь   { 
     интервал   число  ; 
  };    /* тип структуры объекта теперь завершен */ 

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

typedef   struct   Берт   Берт  ; 
  typedef   struct   Вильма   Вильма  ; 

  struct   Bert   { 
     Вилма   *  вилма  ; 
  }; 

  struct   Вильма   { 
     Берт   *  берт  ; 
  }; 

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

Указатели [ править ]

В объявлениях модификатор звездочки ( *) указывает тип указателя. Например, если спецификатор int будет относиться к целочисленному типу, спецификатору int*относится к типу «указатель на целое число». Значения указателя связывают две части информации: адрес памяти и тип данных. Следующая строка кода объявляет переменную с указателем на целое число, называемую ptr :

интервал   *  ПТР  ; 

Ссылка [ править ]

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

интервал   а   =   0  ; 
  интервал   *  ptr   =   a   ; 

Для этого используется оператор «адреса» (унарный &) используется. Он создает местоположение в памяти следующего объекта данных.

Разыменование [ править ]

Доступ к указанным данным можно получить через значение указателя. В следующем примере целочисленной переменной b присваивается значение целочисленной переменной a , равное 10:

интервал   а  =  10  ; 
  интервал   *  п  ; 
  р   =   a   ; 
  интервал   б   =   *  п  ; 

Для выполнения этой задачи используется унарный оператор разыменования , обозначенный звездочкой (*). Он возвращает данные, на которые указывает его операнд, который должен иметь тип указателя. Таким образом, выражение * p обозначает то же значение, что и a . Разыменование нулевого указателя является незаконным.

Массивы [ править ]

Определение массива [ править ]

Массивы используются в C для представления структур последовательных элементов одного и того же типа. Определение массива (фиксированного размера) имеет следующий синтаксис:

int   массив  [  100  ]; 

который определяет массив с именем array для хранения 100 значений примитивного типа int. Если оно объявлено внутри функции, размерность массива также может быть непостоянным выражением, и в этом случае будет выделена память для указанного количества элементов. переменных В большинстве контекстов при дальнейшем использовании упоминание массива преобразуется в указатель на первый элемент массива. sizeof оператор является исключением: sizeof array дает размер всего массива (то есть в 100 раз больше размера int, и sizeof(array) / sizeof(int)вернет 100). Другим исключением является оператор & (адрес), который возвращает указатель на весь массив, например

int   (  *  ptr_to_array  )[  100  ]   =   &  массив  ; 

Доступ к элементам [ править ]

Основным средством доступа к значениям элементов массива является оператор индекса массива. Чтобы получить доступ к i -индексированному элементу массива , синтаксис будет следующим: array[i], который относится к значению, хранящемуся в этом элементе массива.

Нумерация индексов массива начинается с 0 (см. Индексация с отсчетом от нуля ). Таким образом, наибольший разрешенный индекс массива равен количеству элементов в массиве минус 1. Чтобы проиллюстрировать это, рассмотрим массив a, объявленный как содержащий 10 элементов; первый элемент будет a[0] и последний элемент будет a[9].

C не предоставляет возможности автоматической проверки границ использования массива. Хотя логически последний индекс в массиве из 10 элементов должен быть 9, индексы 10, 11 и т. д. могут быть случайно указаны с неопределенными результатами.

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

Индексы массива и арифметика указателей
Элемент Первый Второй Третий н
Индекс массива array[0] array[1] array[2] array[n - 1]
Разыменованный указатель *array *(array + 1) *(array + 2) *(array + n - 1)

Поскольку выражение a[i] семантически эквивалентен *(a+i), что, в свою очередь, эквивалентно *(i+a), выражение также можно записать как i[a], хотя эта форма используется редко.

Массивы переменной длины [ править ]

C99 Стандартизированные массивы переменной длины (VLA) в пределах блока. Такие переменные массива выделяются на основе целочисленного значения во время выполнения при входе в блок и освобождаются в конце блока. [1] Начиная с версии C11, эта функция больше не требуется для реализации компилятором.

интервал   п   =   ...; 
  int   п  [  ]  ; 
  а  [  3  ]   =   10  ; 

Этот синтаксис создает массив, размер которого фиксирован до конца блока.

Динамические массивы [ править ]

Массивы, размер которых можно изменять динамически, можно создавать с помощью стандартной библиотеки C. mallocФункция предоставляет простой метод выделения памяти. Он принимает один параметр: объем выделяемой памяти в байтах. При успешном распределении malloc возвращает общий ( void) значение указателя, указывающее на начало выделенного пространства. Возвращаемое значение указателя неявно преобразуется в соответствующий тип путем присваивания. Если распределение не может быть завершено, mallocвозвращает нулевой указатель . Таким образом, следующий сегмент по функциям аналогичен желаемому объявлению выше:

#include   <stdlib.h>  /* объявляет malloc */ 
 ... 
 int   *  a   =   malloc  (  n   *   sizeof   *  a  ); 
  а  [  3  ]   =   10  ; 

Результатом является «указатель на int"переменная ( a ), которая указывает на первую из n смежных intобъекты; из-за эквивалентности указателя массива его можно использовать вместо фактического имени массива, как показано в последней строке. Преимущество использования этого динамического распределения заключается в том, что объем выделяемой ему памяти может быть ограничен тем, что действительно необходимо во время выполнения, и это можно изменить по мере необходимости (с помощью стандартной библиотечной функции realloc).

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

В целях безопасности некоторые программисты [ ВОЗ? ] затем установите переменную указателя на NULL:

бесплатно  (  а  ); 
  а   =   НОЛЬ  ; 

Это гарантирует, что дальнейшие попытки разыменовать указатель в большинстве систем приведут к сбою программы. Если этого не сделать, переменная станет висячим указателем , что может привести к ошибке использования после освобождения. Однако, если указатель является локальной переменной, установка для него значения NULLне запрещает программе использовать другие копии указателя. Локальные ошибки использования после освобождения обычно легко статическим анализатором распознаются . Следовательно, этот подход менее полезен для локальных указателей и чаще используется с указателями, хранящимися в долгоживущих структурах. Однако в целом установка указателей на NULL это хорошая практика [ по мнению кого? ] поскольку это позволяет программисту NULL-проверяйте указатели перед разыменованием, что помогает предотвратить сбои.

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

int   (  *  a  )[  100  ]   =   malloc  (  sizeof   *  a  ); 

... Что дает указатель на массив.

Доступ к указателю на массив можно осуществить двумя способами:

(  *  а  )[  индекс  ]; 

  индекс  [  *  а  ]; 

Итерацию также можно выполнить двумя способами:

for   (  int   я   =   0  ;   я   <   100  ;   я  ++  ) 
     (  *  a  )[  я  ]; 

  for   (  int   *  я   =   а  [  0  ];   я   <   а  [  1  ];   я  ++  ) 
     *  я  ; 

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

Многомерные массивы [ править ]

Кроме того, C поддерживает многомерные массивы, которые хранятся в порядке следования строк . Технически многомерные массивы C — это просто одномерные массивы, элементы которых являются массивами. Синтаксис объявления многомерных массивов следующий:

int   array2d  [  СТРОКИ  ][  СТОЛБЦЫ  ]; 

где ROWS и COLUMNS — константы. Это определяет двумерный массив. Если читать индексы слева направо, array2d представляет собой массив длиной ROWS , каждый элемент которого представляет собой массив целых чисел COLUMNS .

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

массив2d  [  4  ][  3  ] 

Опять же, читая слева направо, мы получаем доступ к 5-й строке и 4-му элементу в этой строке. Выражение array2d[4] — это массив, которому мы затем присваиваем индекс [3] для доступа к четвертому целому числу.

Индексы массива и арифметика указателей [2]
Элемент Первый Вторая строка, второй столбец i-я строка, j-й столбец
Индекс массива array[0][0] array[1][1] array[i - 1][j - 1]
Разыменованный указатель *(*(array + 0) + 0) *(*(array + 1) + 1) *(*(array + i - 1) + j - 1)

Аналогичным образом можно объявить многомерные массивы.

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

Струны [ править ]

В C строковые литералы заключаются в двойные кавычки ( ") (например, "Hello world!") и компилируются в массив указанных char значения с дополнительным нулевым завершающим символом (0-значным) кодом, обозначающим конец строки.

Строковые литералы не могут содержать встроенные символы новой строки; этот запрет несколько упрощает разбор языка. Чтобы включить новую строку в строку, используйте обратную косую черту. \n можно использовать, как показано ниже.

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

Синтаксис строковых литералов C оказал большое влияние и проник во многие другие языки, такие как C++, Objective-C, Perl, Python, PHP, Java, JavaScript, C# и Ruby. В настоящее время почти все новые языки принимают или основываются на строковом синтаксисе в стиле C. Языки, в которых отсутствует этот синтаксис, обычно предшествуют C.

Обратная косая черта экранируется [ править ]

Поскольку некоторые символы не могут быть частью буквального строкового выражения напрямую, вместо этого они идентифицируются escape-последовательностью, начинающейся с обратной косой черты ( \). Например, обратная косая черта в "This string contains \"double quotes\"." указать (компилятору), что внутренняя пара кавычек предназначена как фактическая часть строки, а не как чтение по умолчанию как разделитель (конечная точка) самой строки.

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

Побег Значение
\\ Буквальная обратная косая черта
\" Двойная кавычка
\' Одиночная цитата
\n Новая строка (перевод строки)
\r Возврат каретки
\b Backspace
\t Горизонтальная вкладка
\f Подача формы
\a Оповещение (звонок)
\v Вертикальная вкладка
\? Вопросительный знак (используется для экранирования триграфов )
%% Процентный знак, только строки формата printf (Примечание \% нестандартно и не всегда распознается)
\OOO Символ восьмеричного значения ООО (где ООО — это 1–3 восьмеричные цифры, от «0» до «7»).
\xHH Символ с шестнадцатеричным значением HH (где HH  – это 1 или несколько шестнадцатеричных цифр, '0'-'9', 'A'-'F', 'a'-'f')

Использование других escape-кодов обратной косой черты не определено стандартом C, хотя поставщики компиляторов часто предоставляют дополнительные escape-коды в качестве расширений языка. Одним из них является escape-последовательность \eдля escape-символа с шестнадцатеричным значением ASCII 1B, который не был добавлен в стандарт C из-за отсутствия представления в других наборах символов (например, EBCDIC ). Он доступен в GCC , clang и tcc .

Конкатенация строковых букв [ править ]

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

    printf  (  __FILE__   ": %d: Привет " 
            "мир  \n  "  ,   __LINE__  ); 

расширится до

    printf  (  "helloworld.c"   ": %d: Привет " 
            "world  \n  "  ,   10  ); 

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

    printf  (  "helloworld.c: %d: Привет, мир  \n  "  ,   10  ); 

Символьные константы [ править ]

Отдельные символьные константы заключаются в одинарные кавычки, например 'A'и иметь тип int (в С++, char). Разница в том, что "A" представляет собой массив из двух символов, завершающийся нулем, 'A' и '\0', тогда как 'A'непосредственно представляет значение символа (65, если используется ASCII). Поддерживаются те же символы обратной косой черты, что и для строк, за исключением того (конечно): " может действительно использоваться как символ без экранирования, тогда как ' теперь нужно бежать.

Символьная константа не может быть пустой (т.е. ''является недопустимым синтаксисом), хотя строка может быть таковой (она по-прежнему имеет завершающий нулевой символ). Многосимвольные константы (например, 'xy') действительны, хотя и редко полезны — они позволяют хранить несколько символов в целом числе (например, 4 символа ASCII могут поместиться в 32-битное целое число, 8 — в 64-битное). Поскольку порядок, в котором символы упакованы в int не указано (оставлено на усмотрение реализации), переносимое использование многосимвольных констант затруднено.

Тем не менее, в ситуациях, ограниченных конкретной платформой и реализацией компилятора, многосимвольные константы находят свое применение при указании сигнатур. Одним из распространенных вариантов использования является OSType , где сочетание классических компиляторов Mac OS и присущий ему обратный порядок байтов означает, что байты в целом числе появляются в точном порядке символов, определенных в литерале. Определения популярных «реализаций» на самом деле совпадают: в GCC, Clang и Visual C ++ '1234' урожайность 0x31323334 под ASCII. [3] [4]

Как и строковые литералы, символьные константы также можно изменять с помощью префиксов, например L'A' имеет тип wchar_t и представляет значение символа «A» в кодировке расширенных символов.

Широкие строки символов [ править ]

Поскольку тип char имеет ширину 1 байт, один charЗначение обычно может представлять не более 255 различных кодов символов, чего недостаточно для всех символов, используемых во всем мире. Чтобы обеспечить лучшую поддержку международных символов, в первом стандарте C (C89) были введены широкие символы (закодированные в виде wchar_t) и строки широких символов, которые записываются как L"Hello world!"

Широкие символы чаще всего имеют длину 2 байта (с использованием 2-байтовой кодировки, например UTF-16 ) или 4 байта (обычно UTF-32 ), но стандарт C не определяет ширину для wchar_t, оставляя выбор за разработчиком. Microsoft Windows обычно использует UTF-16, поэтому для компилятора Microsoft указанная выше строка будет иметь длину 26 байт; мир Unix предпочитает UTF-32, поэтому такие компиляторы, как GCC, будут генерировать 52-байтовую строку. Ширина 2 байта wchar_t имеет те же ограничения, что и char, поскольку определенные символы (вне BMP ) не могут быть представлены в одном wchar_t; но должны быть представлены с использованием суррогатных пар .

Исходный стандарт C определял только минимальные функции для работы с широкими символьными строками; в 1995 году стандарт был изменен и теперь включает гораздо более широкую поддержку, сравнимую с поддержкой charструны. Соответствующие функции в основном названы в честь их charэквиваленты с добавлением буквы «w» или заменой «str» на «wcs»; они указаны в <wchar.h>, с <wctype.h> содержащий функции классификации и сопоставления широких символов.

Сейчас обычно рекомендуемый метод [заметка 3] поддержка международных символов осуществляется через UTF-8 , который хранится в char массивы и могут быть записаны непосредственно в исходном коде при использовании редактора UTF-8, поскольку UTF-8 является прямым расширением ASCII .

Строки переменной ширины [ править ]

Распространенная альтернатива wchar_tзаключается в использовании кодировки переменной ширины , при которой логический символ может занимать несколько позиций строки. Строки переменной ширины могут быть закодированы в литералы дословно, рискуя запутать компилятор, или с использованием числовых символов обратной косой черты (например, "\xc3\xa9"для «é» в UTF-8). Кодировка UTF -8 была специально разработана (в соответствии с Plan 9 ) для совместимости со строковыми функциями стандартной библиотеки; Вспомогательные функции кодирования включают отсутствие встроенных нулей, отсутствие допустимых интерпретаций подпоследовательностей и тривиальную ресинхронизацию. Кодировки, лишенные этих функций, скорее всего, окажутся несовместимыми с функциями стандартной библиотеки; В таких случаях часто используются строковые функции с учетом кодировки.

Библиотечные функции [ править ]

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

Структуры и союзы [ править ]

Структуры [ править ]

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

Союзы [ править ]

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

Декларация [ править ]

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

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

структура   s   { 
     интервал     х  ; 
      плавать   у  ; 
      символ    *  z  ; 
  }   тройник  ; 

И следующий оператор объявит аналогичный союз с именем u и его экземпляр с именем n:

союз   ты   { 
     интервал     х  ; 
      плавать   у  ; 
      символ    *  z  ; 
  }   п  ; 

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

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

структура   с   р  ; 

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

typedef   struct   {...}   s_type  ; 

Будущие операторы могут затем использовать спецификатор s_type (вместо расширенного struct ... спецификатор) для ссылки на структуру.

Доступ к участникам [ править ]

Доступ к членам осуществляется с использованием имени экземпляра структуры или объединения, точки ( .) и имя участника. Например, учитывая объявление tee выше, член, известный как y (типа float) можно получить, используя следующий синтаксис:

тройник  .   й 

Доступ к структурам обычно осуществляется через указатели. Рассмотрим следующий пример, определяющий указатель на tee , известный как ptr_to_tee :

struct   s   *  ptr_to_tee   =   &  тройник  ; 

Доступ к элементу y из tee можно получить, разыменовав ptr_to_tee и используя результат в качестве левого операнда:

(  *  ptr_to_tee  ).   й 

Что идентично более простому tee.yвыше, пока ptr_to_tee указывает на tee . Из-за приоритета операторов ("." выше, чем "*"), чем короче *ptr_to_tee.y некорректен для этой цели, вместо этого он анализируется как *(ptr_to_tee.y)и поэтому скобки необходимы. Поскольку эта операция является распространенной, C предоставляет сокращенный синтаксис для доступа к элементу непосредственно из указателя. При использовании этого синтаксиса имя экземпляра заменяется именем указателя, а точка заменяется последовательностью символов. ->. Таким образом, следующий метод доступа к y идентичен двум предыдущим:

ptr_to_tee  ->  y 

Доступ к членам профсоюзов осуществляется таким же образом.

Это можно связать в цепочку; например, в связанном списке можно обратиться к n->next->next для второго следующего узла (при условии, что n->next не является нулевым).

Назначение [ править ]

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

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

Например, следующий оператор присваивает значение 74 (код ASCII для буквы «t») члену с именем x в структуре tee сверху:

тройник  .   х   =   74  ; 

И то же самое назначение с использованием ptr_to_tee вместо tee будет выглядеть так:

ptr_to_tee  ->  х   =   74  ; 

Распределение с членами союзов идентично.

Прочие операции [ править ]

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

Битовые поля [ править ]

C также предоставляет специальный тип элемента, известный как битовое поле , которое представляет собой целое число с явно указанным числом битов. Битовое поле объявляется как член структуры (или объединения) типа int, signed int, unsigned int, или _Bool, [примечание 4] после имени члена ставится двоеточие ( :) и количество бит, которое оно должно занимать. Общее количество битов в одном битовом поле не должно превышать общее количество битов в его объявленном типе (однако это разрешено в C++, где дополнительные биты используются для заполнения).

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

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

Члены битовых полей не имеют адресов и поэтому не могут использоваться с адресом ( &) унарный оператор. sizeof Оператор не может применяться к битовым полям.

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

struct   f   { 
     unsigned   int    flag   :   1  ;     /* битовый флаг: может быть включен (1) или выключен (0) */ 
     Signed   int      num    :   4  ;     /* 4-битное поле со знаком;   диапазон -7...7 или -8...7 */ 
     Signed   int           :   3  ;     /* 3 бита заполнения для округления до 8 бит */ 
 }   g  ; 

Инициализация [ править ]

Инициализация по умолчанию зависит от спецификатора класса хранения , описанного выше.

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

интервал   х   =   12  ; 
  интервал   у   =   {23}    ;        //Правильно, без предупреждений 
 int   z   =   {   {   34   }   };    //Юридически, ожидайте предупреждение 

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

Следующий оператор инициализирует новый экземпляр структуры, известной как pi :

структура   s   { 
     интервал     х  ; 
      плавать   у  ; 
      символ    *  z  ; 
  }; 

  struct   s   pi   =   {   3  ,   3,1415  ,   "Пи"   }; 

Назначенные инициализаторы [ править ]

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

структура   s   пи   =   {   .   z   =   "Пи"  ,   .   х   =   3  ,   .   у   =   3,1415   }; 

Использование указателя в инициализаторе перемещает «курсор» инициализации. В примере ниже, если MAX больше 10, в середине будут элементы с нулевым значением. a; если оно меньше 10, некоторые значения, предоставленные первыми пятью инициализаторами, будут переопределены вторыми пятью (если MAX меньше 5, будет ошибка компиляции):

int   a  [  MAX  ]   =   {   1  ,   3  ,   5  ,   7  ,   9  ,   [  MAX  -5  ]   =   8  ,   6  ,   4  ,   2  ,   0   }; 

В C89 объединение инициализировалось с использованием одного значения, примененного к его первому члену. То есть объединение u, определенное выше, может иметь только инициализированный член int x :

 объединения   u  значение   =   {3}    ; 

При использовании назначенного инициализатора инициализируемый элемент не обязательно должен быть первым:

союз   u   значение   =   {   .   у   =   3,1415   }; 

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

интервал   Икс  []   знак равно   {   0  ,   1  ,   2   }   ; 

Составные обозначения могут использоваться для обеспечения явной инициализации в неукрашенных списках инициализаторов. может быть неправильно понято. В примере ниже w объявляется как массив структур, каждая структура состоит из члена a (массив из 3 int) и член b (ан int). Инициализатор устанавливает размер w равным 2 и устанавливает значения первого элемента каждого a:

структура   {   интервал   а  [  3  ],   б  ;    }   ш  []   знак равно   {   [  0  ].   а   =   {  1  },   [  1  ].   а  [  0  ]   =   2   }; 

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

структура   {   интервал   а  [  3  ],   б  ;    }   w  []   = 
 { 
    {   {   1  ,   0  ,   0   },   0   }, 
    {   {   2  ,   0  ,   0   },   0   }  
 }; 

В стандарте C невозможно указать повторение инициализатора.

Составные литералы [ править ]

Можно позаимствовать методологию инициализации для создания составной структуры и литералов массива:

// указатель, созданный из литерала массива. 
  int   *  ptr   =   (  int  []){   10  ,   20  ,   30  ,   40   }; 

  // указатель на массив. 
  float   (  *  foo  )[  3  ]   =   &  (  float  []) {   0.5f  ,   1.f  ,   -0.5f   }; 

  struct   s   pi   =   (  struct   s  ){   3  ,   3,1415  ,   "Pi"   }; 

Составные литералы часто комбинируются с назначенными инициализаторами, чтобы сделать объявление более читабельным: [1]

пи   =   (  структура   s  ){   .   z   =   "Пи"  ,   .   х   =   3  ,   .   у   =   3,1415   }; 

Операторы [ править ]

Структуры управления [ править ]

C — язык свободной формы .

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

Сложные утверждения [ править ]

В элементах этого раздела любой <оператор> можно заменить составным оператором . Сложные утверждения имеют вид:

{ 
     <  необязательных  объявлений  список  > 
     <  необязательных  операторов  список  > 
 } 

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

Операторы выбора [ править ]

В C есть два типа операторов выбора : if заявление и switch заявление .

The if заявление имеет вид:

if   (  <  выражение  >  ) 
     <  оператор1  > 
 else 
     <  оператор2  > 

в if заявление, если <expression> в скобках ненулевое значение (истина), управление передается <statement1>. Если else пункт присутствует и <expression> равно нулю (ложь), управление перейдет к <statement2>. else <statement2> часть необязательна и, если отсутствует, является ложным <expression> просто приведет к пропуску <statement1>. Ан else всегда соответствует ближайшему предыдущему несовпадающему if; При необходимости или для ясности можно использовать фигурные скобки, чтобы переопределить это.

The switchОператор вызывает передачу управления одному из нескольких операторов в зависимости от значения выражения , которое должно иметь целочисленный тип . Подоператор, управляемый переключателем, обычно является составным. Любое утверждение в подвыражении может быть помечено одним или несколькими case метки, состоящие из ключевого слова caseза которым следует константное выражение, а затем двоеточие (:). Синтаксис следующий:

switch   (  <  выражение  >  ) 
 { 
     case   <label1>   : 
         <  оператор   1  > 
     case   <label2>  :  
         <  оператор   2  > 
         Break  ; 
      по умолчанию   : 
         <  утверждения   3  > 
 } 

Никакие две регистровые константы, связанные с одним и тем же переключателем, не могут иметь одинаковое значение. Может быть не более одного defaultметка, связанная с переключателем. Если ни одна из меток регистра не равна выражению в круглых скобках после switch, управление переходит к default этикетку или, если ее нет default label, выполнение возобновляется сразу за пределами всей конструкции.

Переключатели могут быть вложенными; а case или default метка связана с самым внутренним switchкоторый содержит его. Операторы переключения могут «провалиться», то есть, когда одна секция случая завершила свое выполнение, операторы будут продолжать выполняться вниз до тех пор, пока не произойдет сбой. break;встречается утверждение. В некоторых случаях провал полезен, но обычно нежелателен. В предыдущем примере, если <label2> достигнуто, утверждения <statements 2>выполняются и больше ничего внутри фигурных скобок. Однако, если <label1> достигается, оба <statements 1> и <statements 2> выполняются, поскольку нет break чтобы разделить два оператора случая.

Можно, хотя и необычно, вставить switchметки в подблоки других управляющих структур. Примеры этого включают устройство Даффа и Саймона Тэтэма реализацию сопрограмм в Putty . [6]

Операторы итерации [ править ]

C имеет три формы оператора итерации :

do 
     <  оператор  > 
 while   (   <  выражение  >   )   ; 

  while   (   <  выражение  >   ) 
     <  оператор  > 

 for   (   <  выражение  >   ;   <  выражение  >   ;   <  выражение  >   ) 
     <  оператор  > 

в while и do операторы, подоператор выполняется повторно до тех пор, пока значение expressionостается ненулевым (эквивалентно истине). С while, тест, включая все побочные эффекты от <expression>, происходит перед каждой итерацией (выполнением <statement>); с do, тест происходит после каждой итерации. Таким образом, do оператор всегда выполняет свой подоператор хотя бы один раз, тогда как while может вообще не выполнить подоператор.

Заявление:

для   (  е1  ;   е2  ;   е3  ) 
     с  ; 

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

е1  ; 
  в то время как   (  е2  ) 
 { 
     s  ; 
  продолжение  : 
     е3  ; 
  } 

кроме поведения continue; заявление (которое в for цикл переходит к e3 вместо e2). Если e2 пусто, его следует заменить на 1.

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

Начиная с C99 , первое выражение может принимать форму объявления, обычно включающего инициализатор, например:

for   (  int   я   =   0  ;   я   <   предел  ;   ++  я  )   { 
     // ... 
 } 

Область применения декларации ограничена степенью for петля.

Операторы перехода [ править ]

Операторы перехода передают управление безоговорочно. существует четыре типа операторов перехода : В C goto, continue, break, и return.

The goto заявление выглядит так:

перейти к   <  идентификатор  >   ; 

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

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

while   (  выражение  ) 
 { 
     /* ... */ 
     cont  :   ; 
  } 

 do 
 { 
     /* ... */ 
     cont  :   ; 
  }   Пока   (  выражение  ); 

  for   (  выражение1  ;   выражение2  ;   выражение3  )   { 
      /* ... */ 
      cont  :   ; 
  } 

а continue не содержащийся во вложенном операторе итерации, то же самое, что goto cont.

The break оператор используется для завершения for петля, while петля, do петля, или switchзаявление. Управление передается оператору, следующему за завершенным оператором.

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

Сохранение адреса метки [ править ]

GCC расширяет язык C унарным &&оператор, возвращающий адрес метки. Этот адрес может быть сохранен в void* тип переменной и может использоваться позже в gotoинструкция. Например, следующие отпечатки "hi " в бесконечном цикле:

    void   *  ptr   =   &&  J1  ; 

  J1  :   printf  (  «привет»  ); 
      перейти к   *  ptr  ; 

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

Функции [ править ]

Синтаксис [ править ]

Определение функции AC состоит из возвращаемого типа ( void если значение не возвращается), уникальное имя, список параметров в скобках и различные операторы:

<  возвращаемого  значения  тип  >   functionName  (   <  параметров  список  >   ) 
 { 
     <  операторы  > 
     return   <  выражение   типа   тип   возвращаемого  значения  >  ; 
  } 

Функция с не- void тип возвращаемого значения должен включать хотя бы один returnзаявление. Параметры задаются <parameter-list>, список объявлений параметров, разделенных запятыми, где каждый элемент в списке представляет собой тип данных, за которым следует идентификатор: <data-type> <variable-identifier>, <data-type> <variable-identifier>, ....

Тип возвращаемого значения не может быть типом массива или типом функции.

int   f  ()[  3  ];       // Ошибка: функция возвращает массив 
 int   (  *  g  ())[  3  ];    // ОК: функция возвращает указатель на массив. 

  пустота   ч  ()();       // Ошибка: функция возвращает функцию 
 void   (  *  k  ())();    // ОК: функция возвращает указатель на функцию 

Если параметров нет, то <parameter-list> можно оставить пустым или указать одним словом void.

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

int   printf   (  const   char  *  ,   ...); 

Манипулировать этими параметрами можно с помощью процедур в заголовке стандартной библиотеки. <stdarg.h>.

Указатели функций [ править ]

Указатель на функцию можно объявить следующим образом:

<  возвращаемого  значения  тип  >   (  <  функции  имя  >  >  )(  <  параметров  список  *  )  ; 

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

#include   <stdio.h> 

 int   (  *  операция  )(  int   x  ,   int   y  ); 

  int   add  (  int   x  ,   int   y  ) 
 { 
     return   x   +   y  ; 
  } 

 int   subtract  (  int   x  ,   int   y  ) 
 { 
     return   x   -   y  ; 
  } 

 int   main  (  int   argc  ,   char  *   args  []) 
 { 
    int    foo   =   1  ,   bar   =   1  ; 

     операция   =   добавить  ; 
     printf  (  "%d + %d = %d  \n  "  ,   foo  ,   bar  ,   операция  (  foo  ,   bar  )); 
     операция   =   вычитание  ; 
     printf  (  "%d - %d = %d  \n  "  ,   foo  ,   bar  ,   операция  (  foo  ,   bar  )); 
     вернуть   0  ; 
  } 

Глобальная структура [ править ]

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

В объявлениях представлены функции , переменные и типы . Функции C подобны подпрограммам Фортрана или процедурам Паскаля .

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

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

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

int   main  ()   {...} 
 int   main  (  void  )   {...} 
 int   main  (  int   argc  ,   char   *  argv  [])   {...} 
 int   main  (  int   argc  ,   char   **  argv  )   {.. .}   // char *argv[] и char **argv имеют тот же тип, что и параметры функции 

Первые два определения эквивалентны (и оба совместимы с C++). Какой из них использовать, вероятно, зависит от индивидуальных предпочтений (текущий стандарт C содержит два примера main() и двое из main(void), но в проекте стандарта C++ используется main()). Возвращаемое значение main (что должно быть int) служит статусом завершения , возвращаемым в хост-среду.

Стандарт C определяет возвращаемые значения. 0 и EXIT_SUCCESS как свидетельство успеха и EXIT_FAILUREкак свидетельство неудачи. ( EXIT_SUCCESS и EXIT_FAILURE определены в <stdlib.h>). Другие возвращаемые значения имеют значения, определяемые реализацией; например, в Linux программа, завершенная сигналом, возвращает код возврата, состоящий из числового значения сигнала плюс 128.

Минимально правильная программа на языке C состоит из пустого main рутина, не принимающая аргументов и ничего не делающая:

int   main  (  void  ) {} 

Потому что нет return заявление присутствует, main возвращает 0 при выходе. [1] (Это особая функция, представленная в C99 и применимая только к main.)

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

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

Функции могут быть написаны программистом или предоставлены существующими библиотеками. Интерфейсы для последнего обычно объявляются путем включения заголовочных файлов — с #include директива предварительной обработки — и объекты библиотеки связываются в окончательный исполняемый образ. Некоторые библиотечные функции, такие как printf, определены стандартом C; они называются стандартными библиотечными функциями.

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

Передача аргумента [ править ]

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

void   incInt  (  int   *  y  ) 
 { 
     (  *  y  )  ++  ;     // Увеличиваем значение 'x' в 'main' ниже на единицу 
 } 

 int   main  (  void  ) 
 { 
     int   x   =   0  ; 
      инкИнт  (  &  х  );     // передаем ссылку на переменную 'x' 
     return   0  ; 
  } 

Функция scanf работает аналогично:

ты   х  ; 
  scanf  (  "%d"  ,   &  x  ); 

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

#include   <stdio.h> 
 #include   <stdlib.h> 

 void   allocate_array  (  int   **   const   a_p  ,   const   int   A  )   { 
 /* 
 выделение массива целых чисел A, 
 присвоение *a_p изменяет 'a' в main() 
 */ 
     *  a_p   =   malloc  (  sizeof  (  int  )   *   A  );  
  } 

 Int   main  (  void  )   { 
     int   *   a  ;    /* создаем указатель на одно или несколько целых чисел, это будет массив */ 

  /* передаем адрес 'a' */ 
     allocate_array  (  &a  a   ,   42  ); 

  /* 'a' теперь является массивом длиной 42, и здесь можно манипулировать и освобождать */ 

     free  (  a  ); 
      вернуть   0  ; 
  } 

Параметр int **a_p является указателем на указатель на int, который является адресом указателя p определено в основной в этом случае функции.

Параметры массива [ править ]

Параметры функции типа массива на первый взгляд могут показаться исключением из правила C передачи по значению. Следующая программа напечатает 2, а не 1:

#include   <stdio.h> 

 void   setArray  (  int   array  [],   int   index  ,   int   value  ) 
 { 
     array  [  index  ]   =   value  ; 
  } 

 Int   main  (  void  ) 
 { 
     int   a  [  1  ]   =   {1}  ; 
      SetArray  (  а  ,   0  ,   2  ); 
      printf   (  "a[0]=%d  \n  "  ,   a  [  0  ]); 
      вернуть   0  ; 
  } 

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

void   setArray  (  int   *  массив  ,   int   индекс  ,   int   значение  ) 

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

Начиная с C99, программист может указать, что функция принимает массив определенного размера, используя ключевое слово static. В void setArray(int array[static 4], int index, int value) первый параметр должен быть указателем на первый элемент массива длиной не менее 4. Также можно добавить квалификаторы ( const, volatile и restrict) к типу указателя, в который преобразуется массив, путем помещения их в скобки.

Анонимные функции [ править ]

Анонимная функция не поддерживается стандартным языком программирования C, но поддерживается некоторыми диалектами C, такими как GCC. [7] и Кланг .

Разное [ править ]

Зарезервированные ключевые слова [ править ]

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

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

Чувствительность к регистру [ править ]

Идентификаторы C чувствительны к регистру (например, foo, FOO, и Fooэто названия разных предметов). Некоторые компоновщики могут сопоставлять внешние идентификаторы с одним регистром, хотя это редкость для большинства современных компоновщиков.

Комментарии [ править ]

Текст, начинающийся с токена /*рассматривается как комментарий и игнорируется. Комментарий заканчивается на следующем */; это может происходить внутри выражений и может занимать несколько строк. Случайное отсутствие терминатора комментария проблематично, поскольку правильно построенный терминатор комментария следующего комментария будет использоваться для завершения исходного комментария, и весь код между комментариями будет рассматриваться как комментарий. Комментарии в стиле C не являются вложенными; то есть случайное размещение комментария внутри комментария приводит к непредвиденным результатам:

/* 
 Эта строка будет проигнорирована. 
  /* 
 Здесь может быть выдано предупреждение компилятора.   Эти строки также будут игнорироваться. 
  Токен открытия комментария выше не запускает новый комментарий, 
 комментария ниже закроет комментарий, начатый в строке 1. 
 / 
 Эта   строка   и   строка   *   ниже   нее   будут   не   игнорироваться   а токен закрытия  .    Оба   , скорее   всего,   приведут к   компиляции   ошибкам  . 
  */ 

Комментарии к строке в стиле C++ начинаются с //и продлить до конца строки. Этот стиль комментариев возник в BCPL и стал допустимым синтаксисом C в C99 ; он недоступен ни в исходном K&R C, ни в ANSI C :

// эта строка будет проигнорирована компилятором 

 /* эти строки 
 будут проигнорированы 
 компилятором */ 

 x   =   *  p  /*q;   /* этот комментарий начинается после 'p' */ 

Аргументы командной строки [ править ]

Параметры , заданные в командной строке, передаются программе C с двумя предопределенными переменными — количеством аргументов командной строки в argc и отдельные аргументы в виде строк символов в массиве указателей. argv. Итак, команда:

мойФилт п1 п2 п3
 

приводит к чему-то вроде:

м и Ф я л т \0 п 1 \0 п 2 \0 п 3 \0
аргв[0] аргв[1] аргв[2] аргв[3]

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

Название программы, argv[0], может быть полезен при печати диагностических сообщений или для использования одного двоичного файла для нескольких целей. Доступ к отдельным значениям параметров можно получить с помощью argv[1], argv[2], и argv[3], как показано в следующей программе:

#include   <stdio.h> 

 int   main  (  int   argc  ,   char   *  argv  []) 
 { 
     printf  (  "argc  \t  = %d  \n  "  ,   argc  ); 
      for   (  int   i   =   0  ;   i   <   argc  ;   i  ++  ) 
         printf  (  "argv[%i]  \t  = %s  \n  "  ,   i  ,   argv  [  i  ]); 
  } 

Порядок оценки [ править ]

В любом достаточно сложном выражении возникает выбор порядка вычисления частей выражения: (1+1)+(3+3) можно оценить в порядке (1+1)+(3+3), (2)+(3+3), (2)+(6), (8), или в порядке (1+1)+(3+3), (1+1)+(6), (2)+(6), (8). Формально соответствующий компилятор C может вычислять выражения в любом порядке между точками последовательности (это позволяет компилятору выполнять некоторую оптимизацию). Точки последовательности определяются:

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

Выражения перед точкой последовательности всегда оцениваются перед выражениями после точки последовательности. В случае короткого замыкания второе выражение может не вычисляться в зависимости от результата первого выражения. Например, в выражении (a() || b()), если первый аргумент имеет ненулевое значение (истина), результат всего выражения не может быть ничем иным, как истина, поэтому b()не оценивается. Аналогично в выражении (a() && b()), если первый аргумент равен нулю (ложь), результат всего выражения не может быть ничем иным, как ложь, поэтому b() не оценивается.

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

 printf  (  "%s %s  \n  "  ,   argv  [  i   =   0  ],   argv  [  ++  i  ]); 

Неопределенное поведение [ править ]

Аспект стандарта C (не уникальный для C) заключается в том, что поведение определенного кода называется «неопределенным». На практике это означает, что программа, созданная из этого кода, может делать что угодно: от работы так, как задумал программист, до сбоя при каждом запуске.

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

#include   <stdio.h> 

 int   main  (  void  ) 
 { 
     int   b   =   1  ; 
      int   a   =   b  ++   +   b  ++  ; 
      printf  (  "%d  \n  "  ,   a  ); 
  } 

++» нет точки последовательности Поскольку между модификациями b в « b ++ + b , можно выполнять этапы оценки более чем в одном порядке, что приводит к неоднозначному утверждению. Это можно исправить, переписав код для вставки точки последовательности, чтобы обеспечить однозначное поведение, например:

а   =   б  ++  ; 
  а   +=   б  ++  ; 

См. также [ править ]

Примечания [ править ]

  1. ^ Перейти обратно: а б The long long Модификатор был введен в стандарт C99 .
  2. ^ Значение auto — это спецификатор типа, а не спецификатор класса хранения в C++0x.
  3. ^ см. в первом разделе UTF-8. ссылки
  4. ^ Также разрешены другие типы, определенные реализацией. C++ позволяет использовать все целочисленные и перечислимые типы, и многие компиляторы C делают то же самое.

Ссылки [ править ]

  1. ^ Перейти обратно: а б с Клеменс, Бен (2012). 21 век С. О'Рейли Медиа . ISBN  978-1449327149 .
  2. ^ Балагурусамы, Э. Программирование на ANSI C. Тата МакГроу Хилл. п. 366.
  3. ^ «Препроцессор C: поведение, определяемое реализацией» . gcc.gnu.org .
  4. ^ «Строковые и символьные литералы (C++)» . Документация по Visual C++ 19 . Проверено 20 ноября 2019 г.
  5. ^ Керниган и Ричи
  6. ^ Тэтэм, Саймон (2000). «Сопрограммы в C» . Проверено 30 апреля 2017 г.
  7. ^ «Выражения операторов (с использованием коллекции компиляторов GNU (GCC))» . gcc.gnu.org . Проверено 12 января 2022 г.
Общий

Внешние ссылки [ править ]

Arc.Ask3.Ru: конец оригинального документа.
Arc.Ask3.Ru
Номер скриншота №: BD6905F5CE66F4EB2305FDDD5A689F1E__1717443300
URL1:https://en.wikipedia.org/wiki/C_syntax
Заголовок, (Title) документа по адресу, URL1:
C syntax - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть, любые претензии не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, денежную единицу можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)