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

Лексемы

Алфавит языка В языке используются все символы латинского алфавита, цифры и некоторые специальные символы. +Состав алфавита Символы латинского алфавитаA, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z Цифры0, 1, 2, 3, 4, 5, 6, 7, 8, 9 Специальные символы, (запятая), ;,. (точка), +, -, *, ^, & (амперсанд), =, ~ (тильда), !, /, <, >, (, ), {, }, [, ], |, %, ?, ' (апостроф), " (кавычки), : (двоеточие), _ (знак подчёркивания), \, # Из допустимых символов формируются лексемы — предопределённые константы, идентификаторы и знаки операций. В свою очередь, лексемы являются частью выражений; а из выражений составляются инструкции и операторы.

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

Символ # не может быть частью никакой лексемы и используется в препроцессоре.

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

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

Встроенный идентификатор только один — __func__, который определяется как константная строка, неявно объявляемая в каждой функции и содержащая её название.

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

Целые числа по умолчанию задаются в десятичной системе счисления. Если указан префикс 0x, то — в шестнадцатеричной системе. Префикс в виде цифры 0 указывает, что число задаётся в восьмеричной системе. Суффикс определяет минимальный размер типа константы, а также определяет, является ли число знаковым или беззнаковым. В качестве итогового типа берётся такой минимально возможный, в котором данную константу можно представить. +Порядок назначения типов данных целым константам согласно их значениюСуффиксДля десятичныхДля восьмеричных и шестнадцатеричныхНетint long

long longint unsigned int

long

unsigned long

long long

unsigned long longu или Uunsigned int unsigned long

unsigned long longunsigned int unsigned long

unsigned long longl или Llong long longlong unsigned long

long long

unsigned long longu или U вместе с l или Lunsigned long unsigned long longunsigned long unsigned long longll или LLlong longlong long unsigned long longu или U вместе с ll или LLunsigned long longunsigned long long

+Примеры записи вещественного числа 1.5Десятичный форматС экспонентойШестнадцатеричный формат1.51.5e+00x1.8p+015e-10x3.0p-10.15e+10x0.cp+1

Константы вещественных чисел по умолчанию имеют тип double. При указании суффикса f константе назначается тип float, а при указании l или L — long double. Константа будет считаться вещественной, если в ней присутствует знак точки, либо буквы p или P в случае шестнадцатеричной записи с префиксом 0x. Десятичная запись может включать экспоненту, указываемую после букв e или E. В случае шестнадцатеричной записи экспонента указывается после букв p или P в обязательном порядке, что отличает вещественные шестнадцатеричные константы от целых. В шестнадцатеричном виде экспонента является степенью числа 2.

Символьные константы заключаются в одинарные кавычки ('), а префикс задаёт как тип данных символьной константы, так и кодировку, в которой символ будет представлен. В Си символьная константа без префикса имеет тип int, в отличие от C++, в котором символьной константе соответствует char. +Префиксы символьных константПрефиксТип данныхКодировкаНетintASCIIuchar16_tКодировка 16-битных многобайтовых строкUchar32_tКодировка 32-битных многобайтовых строкLwchar_tКодировка широких строк Строковые литералы заключаются в двойные кавычки и могут иметь префикс, определяющий тип данных строки и её кодировку. Строковые литералы представляют собой обычные массивы. При этом в многобайтовых кодировках, таких как UTF-8, один символ может занимать более одного элемента массива. По факту строковые литералы являются константными, но в отличие от C++ их типы данных не содержат модификатор const. +Префиксы строковых константПрефиксТип данныхКодировкаНетchar *ASCII или многобайтовая кодировкаu8char *UTF-8uchar16_t *16-битная многобайтовая кодировкаUchar32_t *32-битная многобайтовая кодировкаLwchar_t *Кодировка широких строк Несколько подряд идущих строковых констант, разделённых пробельными символами или переводами строк объединяются в одну строку при компиляции, что часто используется для оформления кода строки путём разделения частей строковой константы по разным строкам для повышения читабельности.

Именованные константы +Сравнение способов задания константМакрос# define BUFFER_SIZE 1024Анонимноеперечислениеenum { BUFFER_SIZE = 1024 };Переменнаяв роликонстантыconst int buffer_size = 1024; extern const int buffer_size; В языке Си для задания констант принято использовать макроопределения, объявляемые с помощью директивы препроцессора #define:

#define имя константы [значение]

Введённая таким образом константа будет действовать в области своей видимости, начиная с момента задания константы и до конца программного кода или до тех пор, пока действие заданной константы не будет отменено директивой #undef: #undef имя константы

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

Для целых чисел существует другой способ создания именованных констант — через перечисления оператора enum. Однако данный метод подходит только для типов, размером меньших либо равных типу int, и не используется в стандартной библиотеке.

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

для указания размера битовых полей, для задания размера массива (за исключением массивов переменной длины), для задания значения элемента перечисления, в качестве значения оператора case.

Ключевые слова Ключевые слова — это идентификаторы, предназначенные для выполнения той или иной задачи на этапе компиляции, либо для подсказок и указаний компилятору. +Ключевые слова языка СиКлючевые словаНазначениеСтандартsizeofПолучение размера объекта на этапе компиляцииC89typedefЗадание альтернативного имени типуauto, registerПодсказки компилятору по месту хранения переменныхexternУказание компилятору искать объект вне текущего файлаstaticОбъявление статического объектаvoidМаркер отсутствия значения; в указателях означает произвольные данныеchar, short,int, longЦелочисленные типы и модификаторы их размераsigned, unsignedМодификаторы целочисленных типов, определяющие их как знаковые или беззнаковыеfloat, doubleВещественные типы данныхconstМодификатор типа данных, указывающий компилятору, что переменные этого типа доступны только для чтенияvolatileУказание компилятору на возможность изменения значения переменной извнеstructТип данных в виде структуры с набором полейenumТип данных, хранящий одно из набора целочисленных значенийunionТип данных, в котором можно хранить данные в представлениях разных типов данныхdo, for, whileОператоры циклаif, elseУсловный операторswitch, case, defaultОператор выбора по целочисленному параметруbreak, continueОператоры прерывания циклаgotoОператор безусловного переходаreturnВозврат из функцииinlineОбъявление встраиваемой функцииC99restrictОбъявление указателя, который ссылается на блок памяти, на который не ссылается никакой другой указатель_BoolБулев тип данных_Complex, _ImaginaryТипы, используемые для вычислений с комплексными числами_AtomicМодификатор типа, делающий его атомарнымC11_AlignasЯвное задание выравнивания в байтах для типа данных_AlignofПолучение выравнивания для заданного типа данных на этапе компиляции_GenericВыбор одного из набора значений на этапе компиляции, исходя из контролируемого типа данных_NoreturnУказание компилятору, что функция не может завершаться нормальным образом (то есть по return)_Static_assertУказание утверждений, проверяемых на этапе компиляции_Thread_localОбъявление локальной для потока переменной

Зарезервированные идентификаторы Помимо ключевых слов стандарт языка определяет зарезервированные идентификаторы, использование которых может привести к несовместимости с будущими версиями стандарта. Зарезервированными являются все, за исключением ключевых, слова, начинающиеся со знака подчёркивания (_), после которого идёт либо заглавная буква (A—Z), либо другой знак подчёркивания. В стандартах С99 и С11 часть таких идентификаторов была использована под новые ключевые слова языка.

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

Также зарезервированными идентификаторами являются все макросы стандартной библиотеки и связываемые на этапе линковки названия из неё.

Использование зарезервированных идентификаторов в программах стандарт определяет как неопределённое поведение. Попытка отмены любого стандартного макроса через #undef также повлечёт за собой неопределённое поведение.

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

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

Следующий стандарт, C99, ввёл ещё один способ оформления комментариев: комментарием считается текст, начинающийся с последовательности символов // и заканчивающийся концом строки.