Вперед Назад Содержание

2. Элементы С

2.1 Введение

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

2.2 Набор символов

Для использования в программах С определено два набора символов: "набор символов С" и "представительный набор символов".

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

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

Все символы программы на С должны быть из набора символов С. Однако, строковые литералы, символьные константы, комментарии и имена файлов в директиве #include могут содержать любой символ из представительного набора.

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

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

Буквы, цифра и подчеркивание

Набор символов С содержит прописные и строчные буквы латинского алфавита, 10 десятичных цифр арабской системы исчисления и символ подчеркивания (_).

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

Компилятор С обрабатывает прописные и строчные буквы, как разные символы. Например, если в идентификаторе использована строчная буква a, Вы не можете заменить ее на прописную букву A, а должны использовать строчную букву.

Разделительные символы

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

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

Знаки пунктуации и специальные символы

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

Таблица 2.1. Знаки пунктуации и специальные символы

Символ Название , запятая . точка ; точка с запятой : двоеточие ? знак вопроса ' одинарная цитатная скобка " двойная цитатная скобка ( левая круглая скобка ) правая круглая скобка [ левая прямоугольная скобка ] правая прямоугольная скобка { левая фигурная скобка } правая фигурная скобка < левая угловая скобка > правая угловая скобка ! восклицательный знак | вертикальная черта / знак деления \ знак обратного деления ~ тильда + плюс # номер % процент & амперсанд ^ крышечка * звездочка - минус = равно
Все эти символы имеют в С специальное значение. В данном руководстве описывается их использование. Любой знак пунктуации из представительной таблицы, не приведенный в Таблице 2.1, может быть использован только в строковых литералах, символьных константах, комментариях и именах файлов в директивах #include.

Управляющие последовательности

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

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

Таблица 2.2. Управляющие последовательности Управляющая Название последовательность \n новая строка \t горизонтальная табуляция \v вертикальная табуляция \b забой \r возврат каретки \f смена листа \a зуммер \' одинарная цитатная скобка \" двойная цитатная скобка \\ обратное деление \ddd восьмеричное значение символа ASCII \xddd шестнадцатеричное значение символа ASCII
Если знак обратного деления предшествует символу, которого нет в Таблице 2.2, то знак обратного деления игнорируется, а сам символ воспринимается буквально. Например, \c представляет собой символ "с" в строковом литерале или символьной константе. Однако, использование строчных букв в управляющих последовательностях зарезервировано для будущей стандартизации. Т.о. хотя появления неопределенных управляющих последовательностей и не вызывает проблем сейчас, потом могут возникнуть проблемы мобильности программного обеспечения.

Последовательность \ddd позволяет задавать любой символ ASCII (Стандартный Код США по Обмену Информацией), указывая его восьмеричный код из трех цифр. Аналогично, последовательность \xddd позволяет задавать любой символ ASCII, указывая его шестнадцатеричный код из трех цифр. Например, пробел можно указать как \b, \010 (восьмеричное значение) или \x008 (шестнадцатеричное значение).

В восьмеричных управляющих последовательностях можно использовать только цифры от 0 до 7. Хотя и не нужно использовать все три цифры (как это показано в предыдущем абзаце), нужно указать хотя бы одну. Например, можно задать символ забоя ASCII в восьмеричном представлении, как \10. Аналогично, можно использовать по крайней мере одну цифру в шестнадцатеричной управляющей последовательности, и опустить вторую и третью цифру. Более того, можно задать пробел в шестнадцатеричном представлении, как \x08 или \x8.

Примечание

При использовании в строках восьмеричного или шестнадцатеричного представления управляющих последовательностей более безопасно задавать все три цифры. Если не задать все три цифры в управляющей последовательности, а за ней непосредственно следует восьмеричное или шестнадцатеричное число, то компилятор интерпретирует этот символ, как часть управляющей последовательности. Например, если напечатать строку "\x07Bell", то результатом будет {ell, т.к. \x07B будет интерпретировано, как левая фигурная скобка ASCII ({). Строка \x007Bell (обратите внимание на два ведущих нуля) является корректным представлением символа зуммера, за которым следует слово Bell. Строка \x7Bell вызовет появление диагностического сообщения компилятора, т.к. шестнадцатеричная величина 7BE слишком велика, чтобы поместиться в один байт.

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

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

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

Операторы

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

В Таблице 2.3 содержится список унарных операторов С с их именами. В Таблице 2.4 содержится список бинарных и тернарных операторов С с их именами. Операторы нужно задавать так, как они показаны в таблицах, без разделительных знаков в многосимвольных операторах. Обратите внимание на то, что три символа операторов (звездочка, знак минуса и амперсанд) появляются в двух таблицах. Их унарная или бинарная интерпретация зависит от контекста, в котором они появляются. Оператор sizeof не включен в эти таблицы. Это скорее ключевое слово (sizeof), чем символ, и поэтому приводится в разделе "Ключевые слова".

Таблица 2.3. "Унарные операторы"

Оператор Название ! логическое НЕ ~ битовое дополнение - арифметическое отрицание * индерекция & адресация + унарный плюс
Оператор унарного плюса выполняется синтаксически, а не семантически.

Таблица 2.4. "Бинарные и тернарные операторы"

Оператор Название + сложение - вычитание * умножение / деление % остаток << сдвиг влево >> сдвиг вправо <= меньше или равно > больше >= больше или равно == эквивалентно != неэквивалентность & битовое И | битовое включающее ИЛИ ^ битовое исключающее ИЛИ |= битовое присвоение включающего ИЛИ && логическое И || логическое ИЛИ , последовательное ?: условие ++ инкремент -- декремент = простое присвоение += присвоение со сложением -= присвоение с вычитанием *= присвоение с умножением /= присвоение с делением %= присвоение с остатком >>= присвоение со сдвигом вправо <<= присвоение со сдвигом влево &= присвоение с битовым И ^= присвоение с битовым исключающим ИЛИ

Оператор условия является тернарным, а не многосимвольным оператором. Условное выражение имеет вид: выражение?выражение:выражение.

Полное описание каждого оператора содержится в главе "Выражения и присвоения".

2.3 Константы

Константа это число, символ или строка символов, которая в программе используется, как значение. Значение константы нельзя изменить.

В языке С есть четыре вида констант: целые, с плавающей точкой, символьные и строковые литералы.

Целые константы

Синтаксис: цифры 0цифры 0xцифры 0Xцифры
"Целая константа" это десятичное, восьмеричное или шестнадцатеричное число, которое представляет собой целое значение в одной из следующих форм: Нельзя разделять цифры в целых константах разделительными цифрами.

В Таблице 2.5 приведены примеры трех форм целых констант.

Таблица 2.5. Примеры целых констант Десятичные Восьмеричные Шестнадцатеричные 10 012 0xa или 0xA 132 0204 0x84 32179 076663 0x7db3 или 0x7DB3

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

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

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

Таблица 2.6. Типы, присваиваемые восьмеричным и шестнадцатеричным константам Шестнадцатеричные Восьмеричные Тип 0x0-0x7FFF 0-077777 int 0x8000-0xFFFF 0100000-0177777 unsigned int 0x10000-0x7FFFFFFF 0200000-017777777777 long 0x80000000-0xFFFFFFFF 020000000000-037777777777 unsigned long
Последовательность непосредственного ввода значений по Таблице 2.6 состоит в том, что шестнадцатеричные и восьмеричные константы всегда дополняются нулями при их преобразовании в в более емкий тип. (Дополнительная информация по преобразованию типа содержится в главе "Выражения и присвоения".

Можно форсировать целую константу в тип long, указав в конце букву l или L. В Таблице 2.7 показаны некоторые формы целых констант long.

Таблица 2.7. Примеры целых констант long Десятичные Восьмеричные Шестнадцатеричные 10L 012L 0xaL или 0xAL 79l 0115l 0x4fl или 0x4Fl
Типы описаны в главе "Объявления", а преобразования описаны в главе "Выражения и присвоения".

Константы с плавающей точкой

Синтаксис: [цифры][.цифры][E|e-[+]цифры]
"Константа с плавающей точкой" это десятичное число, которое соответствует действительному числу со знаком. Значение действительного числа со знаком состоит из целой части, дробной части и показателя степени. "Цифр" может не быть или их может быть несколько (от 0 до 9), а E (или e) это символ экспоненты. Можно опустить либо цифры до десятичной точки (целая часть числа) либо после десятичной точки (дробная часть числа), но не одновременно. Если используется показатель степени, то только в этом случае можно не вводить десятичную точку. Показатель степени состоит из символа экспоненты (E или e) за которым следует постоянное целое значение. Целое значение может быть отрицательным. Нельзя использовать разделительные символы между цифрами или символами константы.

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

Все константы с плавающей точкой имеют тип double.

Примеры

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

15.75 1.575E1 1575e-2 -0.0025 -2.5e-3 25E-4
Можно опустить целую часть константы с плавающей точкой, как это показано в следующих примерах:

-.125 -.175E-2

Символьные константы

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

"Символ" в синтаксисе может быть любым символом из представительной таблицы символов (включая любую управляющую последовательность), кроме одиночной цитатной скобки ('), символа обратного деления (\) или символа новой строки (\n). Для использования в качестве символьной константы одиночной цитатной скобки или символа обратного деления нужно поставить перед ними символ обратного деления, как это показано в Таблице 2.8.

Таблица 2.8. Примеры символьных констант Константа Значение ' ' одиночный пробел 'a' строчная a '?' знак вопроса '\b' забой '\x1B' управляющий символ ASCII '\'' одиночная цитатная скобка '\\' обратное деление
Символьные константы имеют тип int и расширены за счет знака при преобразованиях типов. (Дополнительную информацию можно найти в разделе "Преобразования типов".)

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

Синтаксис: "символы"["символы"]...
Строковый литерал это последовательность символов из представительной таблицы символов, которая заключена в двойные цитатные скобки. Например, строковый литерал может быть таким:

"This is f string literal."
В строковом литерале "символы" могут не содержать вообще или состоять из нескольких символов представительного набора, включая любые управляющие последовательности. Двойная цитатная скобка ("), обратное деление (\) и символ новой строки должны быть представлены их управляющими последовательностями (\", \\ и \n). Непечатные символы также должны быть представлены соответствующими управляющими последовательностями. Каждая управляющая последовательность рассматривается как управляющий символ.

Для форсированного перехода на новую строку в строковом литерале нужно в месте предполагаемого разрыва строки вставить управляющую последовательность перехода на новую строку (\n), следующим образом:

"Enter a number between 1 and 100\nOr press Return"
Традиционный способ формирования строк литералов, которые не умещаются на одной строке, состоит в том, что вводится знак обратного деления и нажимается клавиша RETURN. Знак обратного деление заставляет компилятор игнорировать следующий за ним символ новой строки. Например, строковый литерал

"Long strings can be bro\ ken into two or more pieces."
идентичен строке

"Long strings can be broken into two or more pieces."
Два или несколько строковых литералов, разделенных только символами разделения будут конкатенированы в одну строку. Например, если передать в функцию printf длинные строки как литералы, то они могут быть продолжены с любой колонки следующей строки без возникновения эффекта сдвига при печати:

printf ("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" , string);
Для использования в строковом литерале двойной цитатной скобки или обратного деления нужно перед ним поставить знак обратного деления, как это показано в следующем примере:

"First\\Second" "\"Yes", I do,\" she said."
Обратите внимание на то, что управляющая последовательность (например, \\ или \") в строковом литерале рассматривается как один символ.

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

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

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

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

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

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

Идентификаторы не могут иметь произношение и написание, совпадающее с ключевыми словами языка. Ключевые слова описаны в разделе "Ключевые слова".

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

Примечание

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

Примеры

Приведем ряд примеров для идентификаторов:

j cnt temp1 top_of_page skip12
Прописные и строчные буквы считаются разными символами, поэтому все эти идентификаторы разные:

add ADD Add aDD

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

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

В языке С имеются следующие ключевые слова:

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
Переопределить ключевые слова нельзя. Однако, можно задать текст, который будет заменен ключевыми словами перед компиляцией, используя директивы предпроцессора (см. главу "Функции").

Ключевое слово volatile реализовано синтаксически, но в настоящий момент не имеет какой-либо привязанной к ней семантики. Нельзя использовать volatile в качестве имени переменной в программе.

2.6 Комментарии

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

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

Для подавления компиляции большой части программы или сегмента программы содержащей комментарии, следует заключить нужную часть программы в скобки директив предпроцессора #if и #endif, а не выделять эту часть программы комментариями (см. "Условная компиляция").

Примеры

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

/* Comments can separate and document lines of programm. */ /* Comments can contain keywords such as for and while. */ /***************************************** Comments can occupy several lines. *****************************************/
Комментарии не могут содержать вложенные комментарии. Следующий пример вызовет появление ошибки:

/* You cannot /* nest */ comments */
Ошибка происходит из-за того, что компилятор распознает первое появление */ после слова nest как конец комментария. Он пытается обработать остальной текст и не может этого сделать, поэтому выдает сообщение об ошибке.

2.7 Лексемы

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

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

main() { int i = 0; if (i) elsewhere(); }
Однако, если ввести elsewhere как else where, с пробелом между словами else и where, то в предыдущем примере компилятор выдаст диагностическое сообщение, суть которого состоит в отсутствии точки с запятой после ключевого слова else.

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

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

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

Пример

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

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