Языки программирования C и C Содержание Язык программирования Си Введение 3 Множества символов 4 Константы 10 Идентификаторы 14 Ключевые слова 15 Комментарии 16 Лексемы 17 Исходная программа 18 Исходные файлы 19 Выполнение программ 21 Время жизни и Видимость 22 Классы имен 24 Объявления 27 Спецификаторы типов 28
Область значений величин 29 Деклараторы 30 Объявления переменной 34 Классы памяти 45 Инициализация 51 Объявления типов 54 Имена типов 55 Выражения и присваивания 56 Операнды 57 Операции 63 Операции присваивания 72 Старшинство и порядок выполнения 75 Побочные эффекты 75 Преобразования типов 76 Операторы 80
Функции 90 Язык программирования С Введение 98 Лексика 101 Содержание 643 Синтаксис 106 Область видимости 106 Определения 108 Компоновка 108 Классы памяти 108 Основные типы 109 Производные типы 110 Объекты и LVALUE адреса 110 Символы и целые 111 Преобразования 112 Выражения и операции 114 Описания 127
Спецификаторы класса памяти 128 Описатели 131 Описания классов 137 Инициализация 150 Перегруженные имена функций 157 Описание перечисления 158 Описание Asм 159 Операторы 159 Внешние определения 165 Командные строки компилятора 167 Обзор типов 170 Соображения мобильности 174 Свободная память 175 Справочник по работе с DOS Управление памятью в
DOS 177 Модели памяти 182 Программирование со смешанными моделями и модификаторы адресации 185 Оверлеи VROOMM 192 Математические операции 202 Видео функции 211 Библиотеки DOS 236 Отладчик Turbo Debugger Назначение отладчика 245 Установка и настройка Turbo Debugger 246 Выполнение программ с отладчиком 255 Интерфейс отладчика 269 Содержание 644 Специальные средства
Turbo Debugger 274 Точки останова 281 Окно Log 291 Окно Watches 293 Окно Variables 295 Inspector 297 Окно Stack 299 Вычисление выражений 301 Отладка на уровне ассемблера 308 Отладка в Windows 318 Трассировка исключительных ситуаций операционной системы 325 Отладка объектно ориентированных программ 327 Отладка резидентных программ и драйверов устройств 331
Турбо Си Интегрированная среда разработки 342 Строка меню и меню 342 Окна TURBO C 343 Работа с экранным меню 344 Структура файла, типы данных и операторов ввода вывода 351 Арифметические, логические операции и операции отношения и присваивания 355 Логическая организация программы и простейшее использованиефункций 359 Логическая организация простой программы 360 Использование констант различных типов 360
Управляющие структуры 362 Приемы объявления и обращения к массивам, использование функций и директивы define при работе с массивами 364 Трюки программирования Правило право лево 367 STLport 368 Новый язык программирования от Microsoft C 370 C Builder 372 Применение умных указателей 376 Рассуждения на тему Умных указателей 382 Виртуальные деструкторы 389
Запись структур данных в двоичные файлы 392 Оператор безусловного перехода goto 399 Виртуальный конструктор 403 Чтение исходных текстов 410 Содержание 645 Функция gets 412 Свойства 414 Комментарии 418 Веб программирование 424 Ошибки работы с памятью 429 Создание графиков с помощью ploticus 432 Автоматизация и моторизация приложения 435
Обзор C C компиляторов EMX и Watcom 456 Использование директивы import 462 Создание системных ловушек Windows на Borland C Builder 480 Тонкости и хитрости в вопросах и ответах Приложения Средства для разработчиков 635 Список использованной литературы 640 Содержание 646 Язык программирования Си Введение Си это язык программирования общего назначения, хорошо
известный своей эффективностью, экономичностью, и переносимостью. Указанные преимущества Си обеспечивают хорошее качество разработки почти любого вида программного продукта. Использование Си в качестве инструментального языка позволяет получать быстрые и компактные программы. Во многих случаях программы, написанные на Си, сравнимы по скорости с программами, написанными на языке ассемблера. При этом они имеют лучшую наглядность и их более просто сопровождать.
Си сочетает эффективность и мощность в относительно малом по размеру языке. Хотя Си не содержит встроенных компонент языка, выполняющих ввод вывод, распределение памяти, манипуляций с экраном или управление процессами, тем не менее, системное окружение Си располагает библиотекой объектных модулей, в которой реализованы подобные функции. Библиотека поддерживает многие из функций, которые требуются.
Это решение позволяет изолировать языковые особенности от специфики процессора, на котором выполняется результирующая программа. Строгое определение языка делает его независимым от любых деталей операционной системы или машины. В то же время программисты могут добавить в библиотеку специфические системные программы, чтобы более эффективно использовать конкретной особенности машины. Перечислим некоторые существенные особенности языка
Си ? Си обеспечивает полный набор операторов структурного программирования Си предлагает необычно большой набор операций. Многие операции Си соответствуют машинным командам и поэтому допускают прямую трансляцию Язык программирования Си 3 в машинный код. Разнообразие операций позволяет выбирать их различные наборы для минимизации результирующего кода Си поддерживает указатели на переменные и функции.
Указатель на объект программы соответствует машинному адресу этого объекта. Посредством разумного использования указателей можно создавать эффективно выполняемые программы, так как указатели позволяют ссылаться на объекты тем же самым путем, как это делает машина. Си поддерживает арифметику указателей, и тем самым позволяет осуществлять непосредственный доступ и манипуляции с адресами памяти. В своем составе Си содержит препроцессор, который обрабатывает текстовые
файлы перед компиляцией. Среди его наиболее полезных приложений при написании программ на Си являются определение программных констант, замена вызовов функций аналогичными, но более быстрыми макросами, условная компиляция. Препроцессор не ограничен процессированием только исходных текстовых файлов Си, он может быть использован для любого текстового файла. Си гибкий язык, позволяющий принимать в конкретных ситуациях самые разные решения.
Тем не менее, Си налагает незначительные ограничения в таких, например, действиях, как преобразование типов. Во многих случаях это является достоинством, однако программисты должны хорошо знать язык, чтобы понимать, как будут выполняться их программы. Множества символов В программах на Си используется два множества символов множество символов Си и множество представимых символов. Множество символов
Си содержит буквы, цифры и знаки пунктуации, которые имеют определенное значение для компилятора Си. Программы на Си строятся путем комбинирования в осмысленные конструкции символов из множества Си. Множество символов Си является подмножеством множества представимых символов. Множество представимых символов состоит из всех букв, цифр и символов, которые Язык программирования Си 4 пользователь может представить графически как отдельный символ.
Мощность множества представимых символов зависит от типа терминала, который используется. Программа на Си может содержать только символы из множества символов Си, за исключением строковых литералов, символьных констант и комментариев, где может быть использован любой представимый символ. Каждый символ из множества символов Си имеет вполне определенный смысл для компилятора
Си. Компилятор выдает сообщение об ошибке, когда он встречает неверно использованные символы или символы, не принадлежащие множеству Си. Буквы и цифры Множество символов Си включает большие и малые буквы из английского алфавита и 10 десятичных арабских цифр ? большие английские буквы A B C D E F G H I J K L M N O P Q R 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 t u v w x y z ? десятичные цифры 0 1 2 3 4 5 6 7 8 9
Буквы и цифры используются при формировании констант, идентификаторов и ключевых слов. Все эти конструкции описаны ниже. Компилятор Си рассматривает одну и ту же малую и большую буквы как отличные символы. Если в данной записи использованы малые буквы, то замена малой буквы a на большую букву A сделает отличной данную запись от предшествующей. Пробельные символы Пробел, табуляция, перевод строки, возврат каретки, новая страница, вертикальная
табуляция и новая строка это символы, называемые пробельными, поскольку они имеют то же самое назначение, как и пробелы между словами и строками на печатной странице. Эти символы разделяют объекты, определенные пользователем, такие, как константы и идентификаторы, от других объектов программы. Язык программирования Си 5 Символ CONTROL Z рассматривается как индикатор конца файла.
Компилятор игнорирует любой текст, следующий за символом CONTROL Z. Компилятор Си игнорирует пробельные символы, если они не используются как разделители или как компоненты константы символа или строковых литералов. Это нужно иметь в виду, чтобы дополнительно использовать пробельные символы для повышения наглядности программы например, для просмотра редактором текстов .
Знаки пунктуации и специальные символы Знаки пунктуации и специальные символы из множества символов Си используются для различных целей, от организации текста программы до определения заданий, которые будут выполнены компилятором или откомпилированной программой. Эти символы имеют специальный смысл для компилятора Си. Их использование в языке Си описывается в дальнейшем содержании руководства.
Знаки пунктуации из множества представимых символов, которые не представлены в данном списке, могут быть использованы только в строковых литералах, константах символах и комментариях. ESC!последовательности ESC последовательности это специальные символьные комбинации, которые представляют пробельные символы и не графические символы в строках и символьных константах. Их типичное использование связано со спецификацией таких действий, как возврат каретки и табуляция,
а также для задания литеральных представлений символов, таких как символ двойная кавычка. ESC последовательность состоит из наклонной черты влево, за которой следует буква, знаки пунктуации или комбинация цифр. Если наклонная черта влево предшествует символу, не включенному в этот список, то наклонная черта влево игнорируется, а символ представляется как литеральный. Например, изображение c представляет символ c в литеральной строке или константе символе.
Последовательности ddd и xdd позволяют задать любой символ в ASCII Американский стандартный код Язык программирования Си 6 информационного интерфейса как последовательность трех восьмеричных цифр или двух шестнадцатеричных цифр. Например, символ пробела может быть задан как 010 или x08. Код ASCII нуль может быть задан как 0 или x0. В восьмеричной
ESC последовательности могут быть использованы от одной до трех восьмеричных цифр. Например, символ пробела может быть задан как 10. Точно так же в шестнадцатеричной ESC последовательности могут быть использованы от одной до двух шестнадцатеричных цифр. Так, шестнадцатеричная последовательность для символа пробела может быть задана как x08 или x8. Важно Когда используется восьмеричная или шестнадцатеричная
ESC последовательность в строках, то нужно полностью задавать все цифры ESC последовательности три цифры для восьмеричной и две цифры для шестнадцатеричной ESC последовательностей . Иначе, если символ непосредственно следующий за ESC последовательностью, случайно окажется восьмеричной или шестнадцатеричной цифрой, то он проинтерпретируется как часть последовательности. Например, строка x7Bell при выводе на печать будет выглядеть как ell,
поскольку x7B проинтерпретируется как символ левой фигурной скобки . Строка x07Bell будет правильным представлением символа звонок с последующим словом Bell. ESC последовательности позволяют посылать неграфические управляющие символы к внешним устройствам. Например, ESC последовательность 033 часто используется как первый символ команд управления терминалом и принтером. Неграфические символы всегда должны представляться
ESC последовательностями, поскольку, непосредственное использование в программах на Си неграфических символов будет иметь непредсказуемый результат. Наклонная черта влево помимо определения ESC последовательностей используется также, как символ продолжения строки в препроцессорных определениях. Если символ новая строка следует за наклонной чертой влево, то новая строка игнорируется и следующая строка рассматривается, как часть предыдущей строки.
Язык программирования Си 7 Операции Операции это специальные комбинации символов, специфицирующие действия по преобразованию различных величин. Компилятор интерпретирует каждую из этих комбинаций как самостоятельную единицу, называемую лексемой token. Ниже представлен список операций. Операции должны использоваться точно так, как они тут представлены без пробельных символов между символами в тех операциях, которые представлены несколькими символами.
Операция sizeof не включена в этот список, так как она представляет собой ключевое слово, а не символ Логическое НЕ Побитовое дополнение Сложение ! Вычитание, арифметическое отрицание Умножение Деление Остаток Сдвиг влево Сдвиг вправо Меньше Меньше или равно Язык программирования Си 8 Больше Больше или равно Равно ! Не равно Побитовое
И, адрес от Побитовое включающее ИЛИ Побитовое исключающее ИЛИ Логическое И Логическое ИЛИ Последовательное выполнение запятая ? Операция условного выражения Инкремент Декремент Простое присваивание Сложение с присваиванием ! Вычитание с присваиванием Язык программирования Си 9 Умножение с присваиванием
Деление с присваиванием Остаток с присваиванием Сдвиг вправо с присваиванием Сдвиг влево с присваиванием Побитовое И с присваиванием Побитовое включающее ИЛИ с присваиванием Побитовое исключающее ИЛИ с присваиванием Важно Операция условного выражения ? является тернарной, а не двухсимвольной операцией. Формат условного выражения следующий expression ? expression expression
Константы Константа это число, символ или строка символов. Константы используются в программе как неизменяемые величины. В языке Си различают четыре типа констант целые константы, константы с плавающей точкой, константы символы и строчные литералы. Целые константы Целая константа это десятичное, восьмеричное или шестнадцатеричное число, которое представляет целую величину. Десятичная константа имеет следующий формат представления
digits где digits это одна или более десятичных цифр от 0 до 9. Язык программирования Си 10 Восьмеричная константа имеет следующий формат представления 0 odigits где odigits это одна или более восьмеричных цифр от 0 до 7. Запись ведущего нуля необходима. Шестнадцатеричная константа имеет один из следующих форматов представления 0x hdigits 0X hdigits где hdigits одна или более шестнадцатеричных цифр.
Шестнадцатеричная цифра может быть цифрой от 0 до 9 или буквой большой или малой от A до F. В представлении константы допускается смесь больших и малых букв. Запись ведущего нуля и следующего за ним символа x или X необходима. Пробельные символы не допускаются между цифрами целой константы. Ниже иллюстрируются примеры целых констант. 10 012 0xa или 0xA 132 0204 0x84 32179 076663 0x7dB3 или 0x7DB3
Целые константы всегда специфицируют положительные величины. Если требуется отрицательные величины, то необходимо сформировать константное выражение из знака минус и следующей за ним константы. Знак минус рассматривается как арифметическая операция. Каждая целая константа специфицируется типом, определяющим ее представление в памяти и область значений. Десятичные константы могут быть типа int или long.
Восьмеричные и шестнадцатеричные константы в зависимости от размера могут быть типа int, unsigned int, long или unsigned long. Если константа может быть представлена как int, она специфицируется типом int. Если ее величина больше, чем максимальная положительная величина, которая может быть представлена типом int, но меньше величины, которая представляется в том же самом числе бит как и int, она задается типом unsigned int. Наконец, константа, величина которой больше чем максимальная величина, представляемая
типом unsigned int, задается типом long или unsigned long, если это необходимо. Язык программирования Си 11 Важность рассмотренных выше правил состоит в том, что восьмеричные и шестнадцатеричные константы не содержат знаковых расширений, когда они преобразуются к более длинным типам. Программист может определить для любой целой константы тип long, приписав букву l или L в конец константы. Константы с плавающей точкой Константа с плавающей точкой это действительное десятичное
положительное число. Величина действительного числа включает целую, дробную части и зкспоненту. Константы с плавающей точкой имеют следующий формат представления digits . digits E digits где digits одна или более десятичных цифр от 0 до 9 , а E или e символ экспоненты. Целая или дробная части константы могут быть опушены, но не обе сразу. Десятичная точка может быть опущена толькотогда, когда задана экспонента.
Экспонента состоит из символа экспоненты, за которым следует целочисленная величина экспоненты, возможно отрицательная. Пробельные символы не могут разделять цифры или символы константы. Константы с плавающей точкой всегда специфицируют положительные величины. Если требуются отрицательные величины, то необходимо сформировать константное выражение из знака минус и следующей за ним константы. Знак минус рассматривается как арифметическая операция.
Примеры констант с плавающей точкой и константных выражений 15.75 1.575E1 1575e 2 0.0025 2.5e 3 25e 4 Целая часть константы с плавающей точкой может быть опущена, например .75 Язык программирования Си 12 .0075e2 .125 .175E 2 Все константы с плавающей точкой имеют тип double. Константа!символ Константа символ это буква, цифра, знак пунктуации или ESC символ, заключенные в одиночные кавычки. Величина константы символа равна значению представляющего
ее кода символа. Константа символ имеет следующую форму представления char где char может быть любым символом из множества представимых символов, включая любой ESC символ, исключая одиночную кавычку , наклонную черту влево и символ новой строки. Чтобы использовать одиночную кавычку или наклонную черту влево в качестве константы символа, необходимо вставить перед этими знаками наклонную черту влево.
Чтобы представить символ новой строки, необходимо использовать запись n. Строковые литералы Строковый литерал это последовательность букв, цифр и символов, заключенная в двойные кавычки. Строковый литерал рассматривается как массив символов, каждый элемент которого представляет отдельный символ. Строковый литерал имеет следующую форму представления characters где characters это нуль или более символов из множества представимых символов, исключая двойную кавычку, наклонную черту
влево и символ новой строки. Чтобы использовать символ новой строки в строковом литерале, необходимо напечатать наклонную черту влево, а затем символ новой строки. Наклонная черта влево вместе с символом новой строки будут проигнорированы компилятором, что позволяет формировать строковые литералы, располагаемые более чемв одной строке. Язык программирования Си 13 Например, строковый литерал
Long strings can be bro cken into two pieces. идентичен строке Long strings can be brocken into two pieces. Чтобы использовать двойные кавычки или наклонную черту влево внутри строкового литерала, нужно представить их с предшествующей наклонной чертой влево, как показано в следующем примере This is a string literal First Second Yes, I do, she said. The following line shows a null string
Заметим, что ESC символы такие как и могут появляться в строковых литералах. Каждый ESC символ считается одним отдельным символом. Символы строки запоминаются в отдельных байтах памяти. Символ null или 0 является отметкой конца строки. Каждая строка в программе рассматривается как отдельный объект.
Если в программе содержатся две идентичные строки, то каждая из них будет храниться в отдельном месте памяти. Строчные литералы имеют тип char . Под этим подразумевается, что строка это массив, элементы которого имеют тип char. Число элементов в массиве равно числу символов в строчном литерале плюс один, поскольку символ null отметка конца строки тоже считается элементом массива. Идентификаторы Идентификаторы это имена переменных, функций и меток, используемых в программе.
Идентификатор создается объявлением соответствующей ему переменной или функции. После этого его можно использовать в последующих операторах программы. Идентификатор это последовательность из одной или более букв, цифр или подчерков , которая начинается с буквы или подчерка. Допускается любое число символов в идентификаторе, однако только первые 31 символ распознаются компилятором. Программы, использующие результат работы
Язык программирования Си 14 компилятора, такие как, линкер, могут распознавать меньшее число символов . При использовании подчерков в идентификаторе нужно быть осторожным, поскольку идентификаторы, начинающиеся с подчерка могут совпадать войти в конфликт с именами скрытых системных программ. Примеры идентификаторов temp1 toofpage skip12 Компилятор Си рассматривает буквы верхнего и нижнего регистров как различные символы.
Поэтому можно создать отдельные независимые идентификаторы, которые совпадают орфографически, но различаются большими и малыми буквами. Например, каждый из следующихидентификаторов является уникальным add ADD Add aDD Компилятор Си не допускает идентификаторов, которые имеют ту же самую орфографию, что и ключевые слова. Важно По сравнению с компилятором, сборщик может в большей степени ограничивать количество и тип символов для глобальных идентификаторов, и в отличие от компилятора не делать различия между большими
и малыми буквами. Ключевые слова Ключевые слова это предопределенные идентификаторы, которые имеют специальное значение для компилятора Си. Их можно использовать только так как они определены. Имена объектов программы не могут совпадать с названиями ключевых слов. Список ключевых слов auto double int struct break else long switch case enum register typedef char extern return union Язык программирования Си 15 const float short unsigned continue for signed void
default goto sizeof while do if static volatile Ключевые слова не могут быть переопределены. Тем не менее, они могут быть названы другим текстом, но тогда перед компиляцией они должны быть заменены посредством препроцессора на соответствующие ключевые слова. Ключевые слова const и volatile зарезервированы для будущего использования. Следующие идентификаторы могут быть ключевыми словами для некоторых приложений cdecl far fortran huge
near pascal Комментарии Комментарий это последовательность символов, которая воспринимается компилятором как отдельный пробельный символ или, другими словами, игнорируется. Комментарий имеет следующую форму представления characters где characters может быть любой комбинацией символов из множества представимых символов, включая символы новой строки, но исключая комбинацию . Это означает, что комментарии могут занимать более одной строки, но не могут быть вложенными.
Комментарии допускаются везде, где разрешены пробельные символы. Компилятор игнорирует символы комментария, в частности, в комментариях допускается запись ключевых слов и это не приведет к ошибке. Так как компилятор рассматривает комментарий как символ пробела, то комментарии не могут появляться внутри лексем. Язык программирования Си 16 Следующие примеры иллюстрируют некоторые комментарии
Comments can separate and document lines of a program. Comments can contain keywords such as for and while Comments can occupy several lines. Так как комментарии не могут содержать вложенных комментариев, то следующий пример будет ошибочным You cannot nest comments Компилятор распознает первую комбинацию после слова nest как конец комментария.
Затем, компилятор попытается обрабатывать оставшийся текст и выработает сообщение об ошибке. Чтобы обойти компиляцию комментариев больших размеров, нужно использовать директиву if препроцессора. Лексемы Когда компилятор обрабатывает программу, он разбивает программу на группы символов, называемых лексемами. Лексема это единица текста программы, которая имеет определенный смысл для компилятора и которая не может быть разбита в дальнейшем. Операции, константы, идентификаторы и ключевые слова, описанные
в этом разделе, являются примерами лексем. Знаки пунктуации, такие как квадратные скобки, фигурные скобки, угловые скобки, круглые скобки и запятые, также являются лексемами. Границы лексем определяются пробельными символами и другими лексемами, такими как операции и знаки пунктуации. Чтобы предупредить неправильную работу компилятора, запрещаются пробельные символы между символами идентификаторов, операциями, состоящими из нескольких символов и символами ключевых слов.
Когда компилятор выделяет отдельную лексему, он последовательно объединяет столько символов, сколько возможно, прежде чем перейти к обработке следующей лексемы. Поэтому лексемы, не разделенные пробельными символами, могут быть проинтерпретированы неверно. Язык программирования Си 17 Например, рассмотрим следующее выражение i j В этом примере компилятор вначале создает из трех знаков плюс самую длинную из возможных операций ,
а затем обработает оставшийся знак , как операцию сложения . Выражение проинтерпретируется как i j , а не как i j . В таких случаях необходимо использовать пробельные символы или круглые скобки, чтобы однозначно определить ситуацию. Исходная программа Исходная программа это совокупность следующих объектов директив, указаний компилятору, объявлений и определений. Директивы задают действия препроцессора по преобразованию текста
программы перед компиляцией. Указания компилятору это команды, выполняемые компилятором во время процесса компиляции. Объявления задают имена и атрибуты переменных, функций и типов, используемых в программе. Определения это объявления, определяющие переменные и функции. Определение переменной в дополнении к ее имени и типу задает начальное значение объявленной переменной. Кроме того, определение предполагает распределение памяти для переменной.
Определение функции специфицирует ее структуру, которая представляет собой смесь из объявлений и операторов, которые образуют саму функцию. Определение функции также задает имя функции, ее формальные параметры и тип возвращаемой величины. Исходная программа может содержать любое число директив, указаний компилятору, объявлений и определений. Любой из объектов программы имеет определенный синтаксис, описанный в этом руководстве, и каждая составляющая может появляться в любом порядке, хотя влияние порядка, в котором
следуют переменные и функции может быть использовано в программе. Нетривиальная программа всегда содержит более одного определения функции. Функция определяет действия, выполняемые программой. Язык программирования Си 18 В следующем примере иллюстрируется простая исходная программа на языке Си. int x 1 Variable definitions int y 2 extern int printf char ,
Function declaration main Function definition for main function int z Variable declarations int w z y x Executable statements w y x printf z d nw d n , z, x Эта исходная программа определяет функцию с именем main и объявляет функцию printf. Переменные x и y задаются своими определениями. Переменные z и w только объявляются. Исходные файлы Исходные программы могут быть разделены на несколько файлов.
Исходный файл Си это текстовый файл, который содержит часть или всю исходную программу. Он может, например, содержать только некоторые функции, требуемые программе. При компиляции исходной программы каждый из исходных файлов должен быть прокомпилирован отдельно, а затем обработан сборщиком. Отдельные исходные файлы перед компиляцией можно соединять в один большой исходный файл посредством директивы include. Исходный файл может содержать любую комбинацию наборов
директив, указаний компилятору, объявлений и определений. Такие объекты, как определения функций или большие структуры данных, не могут разрываться, начинаясь в одном файле и продолжаясь в другом. Исходный файл не обязательно должен содержать выполняемыеоператоры. Иногда полезно размещать описания переменных в одном файле с тем, чтобы использовать их путем объявления ссылок из других файлов. В этом случае определения становятся легко доступными для поиска и модификации.
Из тех же самых соображений константы и макросы часто организуют в отдельных include файлах и включают их, если требуется, в исходные файлы. Язык программирования Си 19 Директивы исходного файла относятся только к этому исходному файлу и файлам, включающим его посредством include . Кроме того, каждая директива относится только к части файла, которая следует за ней. Если множество директив должно относиться ко всей исходной программе, то все исходные файлы должны
содержать эти директивы. Указания компилятору обычно эффективны для отдельных областей исходного файла. Специфические действия компилятора, задаваемые указаниями, определяются содержанием последних. В нижеследующем примере исходная программа состоит из двух исходных файлов. Функции main и max представлены в отдельных файлах. Функция main использует функцию max при своем выполнении.
Sourse file 1 main function define ONE 1 define TWO 2 define THREE 3 extern int max int, int Function declaration main Function definition int w ONE, x TWO, y THREE int z 0 z max x,y w max z,w Sourse file 2 max function int max a,b Function definition int a, b if a b return a else return b В первом исходном файле функция max объявлена без ее определения.
Это объявление известно как forward объявление. Определение функции main включает вызов функции max. Язык программирования Си 20 Строки, начинающиеся с символа номер , являются директивами препроцессора. Директивы инструктируют препроцессор о замене в первом исходном файле имен ONE, TWO, THREE на соответствующие им значения. Область действия директив не распространяется на второй исходный файл. Второй исходный файл содержит описание функции max.
Это определение соответствует вызовам max из первого исходного файла. Выполнение программ Каждая программа содержит главную программную функцию. В Си главная программная функция должна быть поименована как main. Функция main служит точкой старта при выполнении программы и обычно управляет выполнением программы, организуя вызовы других функций. Программа обычно завершает выполнение по окончанию функции main, хотя
она может завершиться и в других точках, в зависимостиот окружающей обстановки. Исходная программа обычно включает в себя несколько функций, каждая из которых предназначена для выполнения определенного задания. Функция main может вызывать эти функции с тем, чтобы выполнить то или иное задание. Функция возвращает управление при выполнении оператора return или по окончанию самой функции выход на конец функции . Все функции, включая функцию main, могут быть объявлены с параметрами.
Вызываемые функции получают значения параметров из вызывающих функций. Значения параметров функции main могут быть переданы из внешнего окружения. Например, они могут быть переданы из командной строки. Соглашение Си требует, чтобы первые два параметра функции main назывались argc и argv. Параметр argc определяет общее число аргументов, передаваемых функции main.
Параметр argv объявляется как массив указателей, каждый элемент которого ссылается на строковое представление аргумента, передаваемого функции main. Третий параметр функции main если он есть традиционно Язык программирования Си 21 задается с именем envp. Однако Си не требует этого имени. Параметр envp это указатель на массив указателей строковых величин, которые определяют окружение, в котором выполняется программа.
Операционная система поддерживает передачу значений для argc, argv и envp параметров, а пользователь поддерживает задание значений фактических параметров для функции main. Соглашение о передаче параметров в большей степени определяется операционной системой, чем самим языком Си. Формальные параметры функции должны быть объявлены во время описания функции. Время жизни и Видимость Концепции Время жизни и Видимость являются очень важными для понимания структуры
программ на Си. Время жизни переменной может быть или глобальным или локальным. Объект с глобальным временем жизни характеризуется определенной памятью и значением на протяжении всей жизни программы. Объект с локальным временем жизни захватывает новую память при каждом входе в блок, в котором он определен или объявлен. Когда блок завершается, локальный объект пропадает, а следовательно пропадает его значение. Определение блоков описывается ниже.
Объект считается видимым в блоке или исходном файле, если известны тип и имя объекта в блоке или исходном файле. Объект может быть глобально видимым, когда имеется в виду, что он видим или может быть объявлен видимым на протяжении всего исходного файла, образующего программу. Блок это составной оператор. Составные операторы состоят из объявлений и операторов. Структура функции представляет собой совокупность составных операторов.
Таким образом, функции имеют блочную структуру, блоки, в свою очередь, могут содержать внутри себя другие блоки. Объявления и определения внутри блоков находятся на внутреннем уровне. Объявления и определения вне блоков находятся на внешнем уровне. Переменные и функции могут быть объявлены как на внешнем уровне, так и на внутреннем. Язык программирования Си 22 Переменные также могут быть определены на внутреннем и на внешнем уровне,
а функции определяются только на внешнем уровне. Все функции имеют глобальное время жизни, невзирая на то, где они объявлены. Переменные, объявленные на внешнем уровне, всегда имеют глобальное время жизни. Переменные, объявленные на внутреннем уровне, всегда имеют локальное время жизни, однако, классы памяти, специфицированные как static и extern, могут быть использованы для объявления глобальных переменных или ссылок на них внутри блока. Переменные, объявленные или определенные на внешнем уровне, видимы из
точки, в которой они объявлялись или определялись, до конца файла. Однако, переменные, заданные классом памяти static на внешнем уровне, видимы только внутри исходного файла, в котором они определены. В общем случае, переменные, объявленные или определенные на внутреннем уровне, видимы от точки, в которой они объявлены или определены, до конца блока, в котором представлены объявления или определения. Эти переменные называются локальными.
Если переменная, объявленная внутри блока, имеет то же самое имя, как и переменная, объявленная на внешнем уровне, то определение переменной в блоке заменяет имеет предпочтение определение внешнего уровня на протяжении блока. Видимость переменной внешнего уровня восстанавливаетсяпри завершении блока. Блочная видимость может вкладываться. Это значит, что блок, вложенный внутрь другого блока, может содержать объявления, которые переопределяют переменные, объявленные во внешнем блоке.
Переопределение переменной имеет силу во внутреннем блоке, но первоначальное определение восстанавливается, когда управление возвращается внешнему блоку. Переменные из внешних блоков видимы внутри всех внутренних блоков до тех пор, пока они не переопределены во внутреннем блоке. Функции класса памяти static видимы только в исходном файле, в котором они определены. Все другие функции являются глобально видимыми. Язык программирования
Си 23 В следующем примере программы иллюстрируются блоки, вложения и видимость переменных. i defined at external level int i 1 main function defined at external level main prints 1 value of external level i printf d n , i first nested block i and j defined at internal level int i 2, j 3 prints 2, 3 printf d n d n , i, j second nested block i is redefined int i 0 prints 0, 3 printf d n d n , i, j end of second nested block prints 2 outer definition restored printf d n , i end of first nested block prints 1 external
level definition restored printf d n , i В этом примере показано четыре уровня видимости самый внешний уровень и три уровня, образованных блоками. Предполагается, что функция printf определена где нибудь в другом месте программы. Функция main печатает значения 1, 2, 3, 0, 3, 2, 1. Классы имен В любой программе на Си имена используются для ссылок на различного рода объекты. Когда пишется программа на Си, то в ней используются идентификаторы для именования функций,
Язык программирования Си 24 переменных, формальных параметров, областей памяти и других объектов программы. По определенным правилам в Си допускаются использование одного и того же идентификатора для более чем одного программного объекта. Чтобы различать идентификаторы для различного рода объектов, компилятор устанавливает так называемые Классы имен. Для избегания противоречий, имена внутри одного класса должны быть уникальными, однако в различных классах могут появляться идентичные имена.
Это означает, что можно использовать один и тот же идентификатор для двух или более различных объектов, если объекты принадлежат к различным классам имен. Однозначное разрешение ссылок компилятор осуществляет по контексту данного идентификатора в программе. Ниже описываются виды объектов, которые можно именовать в программе на Си, а также правила их именования. Имена переменныхи функций относятся к одному классу имен вместе с
формальными параметрами и перечислимыми константами. Поэтому, имена переменных и функций этого класса должны быть отличны от других имен с той же видимостью. Однако, имена переменных могут быть переопределены внутри программных блоков. Имена функций также могу быть переопределены в соответствии с правилами видимости. Имена формальных параметров функции появляются вместе с именами переменных функции, поэтому имена формальных
параметров должны быть отличны от имен переменных. Переобъявление формальных параметров внутри функции приводит к ошибке. Перечислимые константы относятся к тому же классу имен, что и имена переменных и функций. Это означает, что имена перечислимых констант должны быть отличны от имен всех переменных и функций с той же самой видимостью. Однако, подобно именам переменных, имена перечислимых констант имеют вложенную
видимость, а это означает, что они могут быть переопределены внутри блоков. Имена typedef относятся к одному классу имен вместе с именами переменных и функций. Поэтому они должны быть Язык программирования Си 25 отличны от всех имен переменных и функций с той же самой видимостью, а также от имен формальных параметров и перечислимых констант. Подобно именам переменных, имена, используемые для typedef типов могут быть переопределены внутри блоков
программы. Теги перечислений, структур и совмещений сгруппированы вместе в одном классе имен. Каждый тег перечисления, структуры или соединения должен быть отличен от других тегов с той же самой видимостью. Теги не конфликтуют с любыми другими именами. Элементы каждой структуры или совмещения образуют класс имен, поэтому имя элемента должно быть уникальным внутри структуры или совмещения, но это не означает, что они должны быть отличными от любого другого
имени в программе, включая имена элементов других структур и совмещений. Метки операторов формируют отдельный класс имен. Каждая метка оператора должна быть отлична от всех других меток операторов в той же самой функции. Метки операторов могут совпадать с именами меток других функций. Пример struct student char student 20 int class int id student В этом примере имя тега структуры, элемента структуры и переменной относятся к трем различным классам
имен, поэтому не будет противоречия между тремя объектами с именем student. Компилятор определит по контексту программы как интерпретировать каждый из случаев. Например, когда имя student появится после ключевого слова struct, это будет означать, что появился tag структуры. Когда имя student появится после операции выбора элемента или то это означает, что имя ссылается на элемент структуры. В другом контексте имя student является переменной структурного типа.
Язык программирования Си 26 Объявления Объявления Си имеют следующий синтаксис sc specifier type specifier declarator initializer , declarator initializer , где sc!specifier Спецификатор класса памяти. type!specifier Имя определяемого типа. declarator Идентификатор, который может быть модифицирован при объявлении указателя, массива или функции. initializer Задает значение или последовательность значений, присваиваемых переменной
при объявлении. Все переменные Си должны быть явно объявлены перед их использованием. Функции Си могут быть объявлены явно или неявно в случае их вызова перед определением. Язык Си определяет стандартное множество типов данных. К этому множеству можно добавлять новые типы данных посредством их объявлений на типах данных уже определенных. Объявление Си требует одного или более деклараторов.
Декларатор это идентификатор, который может быть определен с квадратными скобками , звездочкой или круглыми скобками для объявления массива, указателя или функции. Когда объявляется простая переменная такая как символ, целое или плавающее , структура или совмещение простых переменных, то декларатор это идентификатор. В Си определено четыре спецификатора класса памяти, а именно auto, extern, register и static.
Спецификатор класса памяти определяет, каким образом объявляемый объект запоминается и инициализируется и из каких частей программы можно ссылаться на него. Расположение объявления внутри программы, а также наличие или отсутствие других объявлений также важные факторы при определении видимости переменных. Язык программирования Си 27 Спецификаторы типов Язык Си поддерживает определения для множествабазовых типов данных, называемых
основными типами. signed char float void signed int double signed short int signed long int unsigned char unsigned int unsignet short int unsigned long int Перечислимые типы также рассматриваются как основные типы. Типы signed char, signed int, signed short int и signed long int вместе с соответствующими двойниками unsigned называются типами целых. Спецификаторы типов float и double относятся к типу плавающих.
В объявлениях переменных и функций можно использовать любые спецификаторы целый и плавающий. Тип void может быть использован только для объявления функций, которые не возвращают значения. Можно задать дополнительные спецификаторы типа путем объявления typedef. При записи спецификаторов типов допустимы сокращения. В целых типах ключевое слово signed может быть опущено.
Так, если ключевое слово unsigned опускается в записи спецификатора типа, то тип целого будет знаковым, даже если опущено ключевое слово signed. В некоторых реализациях могут быть использованы опции компилятора, позволяющие изменить умолчание для типа char со знакового на беззнаковый. Когда задана такая опция, сокращение char имеет то же самое значение, что и unsigned char, и следовательно ключевое слово sidned должно быть записано при объявлении символьной величины со знаком.
Тип char используется для запоминания буквы, цифры или символа из множества представимых символов. Значением объекта типа char является ASCII код, соответствующий данному Язык программирования Си 28 символу. Так как тип char интерпретируется как однобайтовая целая величина с областью значений от 128 до 127, то только величины от 0 до 127 имеют символьные эквиваленты. Аналогично, тип unsigned char может запоминать величины с областью значений от 0 до 255.
Заметим, что представление в памяти и область значений для типов int и unsigned int не определены в языке Си. По умолчанию размер int со знаком и без знака соответствует реальному размеру целого на данной машине. Например, на 16 ти разрядной машине тип int всегда 16 разрядов или 2 байта. На 32 х разрядной машине тип int всегда 32 разряда или 4 байта. Таким образом, тип int эквивалентен типам short int или long int в зависимости от реализации.
Аналогично, тип unsigned int эквивалентен типам unsigned short или unsigned long. Спецификаторы типов int и unsigned int широко используются в программах на Си, поскольку они позволяют наиболее эффективно манипулироватьцелыми величинами на данной машине. Однако, размер типов int и unsigned int переменный, поэтому программы, зависящие от специфики размера int и unsigned int могут быть непереносимы. Переносимость кода можно улучшить путем включения выражений
с sizeof операцией. Область значений величин Область значений величин это интервал целых величин от минимального до максимального, который может быть представлен в заданном числе бит. Например, константное выражение 32768 состоит из арифметического отрицания , предшествующего величине константы 32768. Так как 32768 это слишком большое значение для типа short, то оно задается типом long и следовательно константное выражение 32768 будет иметь тип long.
Величина 32768 может быть представлена как short только путем преобразования ее типа к типу short. Информация не будет потеряна при преобразовании типа, поскольку 32768 может быть представлено двумя байтами памяти. Аналогично такая величина, как 65000 может быть представлена как unsigned short только путем преобразования ее к типу unsigned short или заданием величины в восьмеричном или шестнадцатеричном представлении. Величина 65000 в Язык программирования
Си 29 десятичном представлении рассматривается как знаковая и задается типом long, так как 65000 не соответствует типу short. Эта величина типа long может быть преобразована к типу unsigned short без потери информации, так как 65000 можно разместить в двух байтах памяти. Восьмеричные и шестнадцатеричные константы могут быть знакового и беззнакового типа в зависимости от их размера. Однако, метод, используемый для назначения типов этим константам гарантирует, что они всегда
будут преобразованы к беззнаковому целому. Числа с плавающей точкой используют IEEE институт инженеров электриков и электронщиков формат. Величины типа float занимают 4 байта, состоящих из бита знака и 7 ми битовой избыточной экспоненты и 24 х битовой мантиссы. Мантисса представляет число между 1.0 и 2.0. Так как старший бит мантиссы всегда 1, он не запоминается в памяти.
Это представление дает область значений приблизительно от 3.4E 38 до 3.4E38. Величины типа double занимают 8 байт. Их формат аналогичен float формату, за исключением того, что порядок занимает 11 бит, а мантисса 52 бита плюс бит, который опущен. Это дает область значений приблизительно от 1.7E 308 до 1.7E 308. Деклараторы Синтаксис identifier declarator declarator constant expression declarator declarator declarator
arg type list declarator Си позволяет объявлять массивы величин, указатели на величины, величины возвратов функций. Чтобы объявить эти объекты, нужно использовать декларатор, возможно модифицированный квадратными скобками , круглыми скобками и звездочкой , что соответствует типам массива, функции или указателя. Деклараторы появляются в объявлениях указателей, массивов и функций. Язык программирования Си 30 Деклараторы массивов, функций и указателей
Когда декларатор состоит из немодифицируемого идентификатора, то объект, который объявляется, имеет немодифицированный тип. Звездочка, которая может появиться слева от идентификатора, модифицирует его в тип указателя. Если за идентификатором следуют квадратные скобки , то тип модифицируется на тип массива. Если за идентификатором следуют круглые скобки, то тип модифицируется на тип функции. Сам по себе декларатор не образует полного объявления.
Для этого в объявление должен быть включен спецификатор типа. Спецификатор типа задает тип элементов массива или тип адресуемых объектов и возвратов функции. Следующие примеры иллюстрируют простейшие формы деклараторов 1. int list 20 2. char cp 3. double func void , где 1. Массив list целых величин 2. Указатель cp на величину типа char 3. Функция func без аргументов, возвращающая величину double.
Составные деклараторы Любой декларатор может быть заключен в круглые скобки. Обычно, круглые скобки используются для спецификации особенностей интерпретации составного декларатора. Составной декларатор это идентификатор, определяемый более чем одним модификатором массива, указателя или функции. С отдельным идентификатором могут появиться различные комбинации модификаторов массива, указателя или функции. Некоторые комбинации недопустимы.
Например, массив не может быть композицией функций, а функция не может возвратить массив или функцию. При интерпретации составных деклараторов квадратные и круглые скобки справа от идентификатора имеют приоритет перед звездочкой слева от идентификатора . Квадратные или круглые скобки имеютодин и тот же приоритет и рассматриваются слева направо. Спецификатор типа рассматривается на последнем шаге, когда
Язык программирования Си 31 декларатор уже полностью проинтерпретирован. Можно использовать круглые скобки, чтобы изменить порядок интерпретации на необходимый в данном случае. При интерпретации составных деклараторов может быть предложено простое правило, которое читается следующим образом изнутри наружу . Нужно начать с идентификатора и посмотреть вправо, есть ли квадратные или круглые скобки. Если они есть, то проинтерпретировать эту часть декларатора, затем посмотреть налево, если ли
звездочка. Если на любой стадии справа встретится закрывающая круглая скобка, то вначале необходимо применить все эти правила внутри круглых скобок, а затем продолжить интерпретацию. На последнем шаге интерпретируется спецификатор типа. В следующем примере проиллюстрированы эти правила. Последовательность шагов при интерпретации перенумерована.
Деклараторы со специальными ключевыми словами Можно использовать следующие специальные ключевые слова cdecl far fortran huge near pascal Эти ключевые слова используются для изменения смысла объявлений переменной и функции. Когда специальное ключевое слово встречается в деклараторе, то оно модифицирует объект, расположенный справа от ключевого слова. Допускается более одного ключевого слова, модифицирующего объект. Например, идентификатор функции может быть модифицирован двумя ключевыми словами far и pascal.
Порядок ключевых слов в этом случае не важен, то есть far pascal и pascal far имеют один и тот же смысл. В различных частях объявления могут быть использованы два или более ключевых слов для модификации смысла составляющих частей объявления. Язык программирования Си 32 Например, в следующем объявлении содержится в различных местах два ключевых слова far и ключевое слово pascal int far pascal far func void Идентификатор функции func модифицируется ключевыми словами
pascal и far. func возвращает величину, объявленную как far указатель на величину типа int. Как и прежде в любом объявлении могут быть использованы круглые скобки для изменения порядка интерпретации. Правила интерпретациисоставных объявлений со специальными ключевыми словами остаются теми же, что и без них. В следующих примерах показано использование специальных ключевых слов в объявлениях. Example 1 int huge database 65000 Example 2 char far x
Example 3 double near cdecl calc double,double double cdecl near calc double,double Example 4 char far fortran initlist INITSIZE char far nextchar, far prevchar, far currentchar Example 5 char far far getint int far 6 5 2 1 3 4 В первом примере объявляется массив huge, поименованный database, содержащий 65000 элементов типа int. Декларатор массива модифицируется ключевым словом huge. Во втором примере ключевое слово far модифицирует расположенную справа звездочку, делая x far указателем
на указатель к величине типа char. Это объявление эквивалентно и такой записи char far x В третьем примере показано два эквивалентных объявления. Оба объявляют calc как функции с near и cdecl атрибутами. В четвертом примере также представлено два объявления первое объявляет far fortan массив символов, поименованный Язык программирования Си 33 initlist, а второе объявляет три far указателя, поименованные
nexchar, prevchar и currentchar. Указатели могут быть использованы для запоминания адресов символов массива initlist. Заметим, что ключевое слово far должно быть повторено перед каждым декларатором. В пятом примере показано более сложное объявление с различными случаями расположения ключевого слова far. Интерпретация этого объявления состоит из следующих шагов 1. Идентификатор getint объявляется как 2. far указатель на 3. функцию, требующую 4. один аргумент, который
является far указателем на величину типа int 5. и возвращающую far указатель на 6. величину типа char Заметим, что ключевое слово far всегда модифицирует объект, который следует справа. Объявления переменной Объявление простой переменной Синтаксис type specifier identifier , identifier Объявление простой переменной определяет имя переменной и ее тип оно может также определять класс памяти переменной.
Имя переменной это идентификатор, заданный в объявлении. Спецификатор типа type specifier задает имя определяемого типа данных. Можно определить имена различных переменных в том же самом объявлении, задавая список идентификаторов, разделенных запятой. Каждый идентификатор списка именует переменную. Все переменные, заданные в объявлении, имеют один и тот же тип.
Примеры int x Example 1 unsigned long reply, flag Example 2 Язык программирования Си 34 double order Example 3 В первом примере объявляется простая переменная x. Эта переменная может принимать любое значение из множества значений, определяемых для типа int. Во втором примере объявлены две переменные reply и flag.
Обе переменные имеют тип unsigned long. В третьем примере объявлена переменная order, которая имеет тип double. Этой переменной могут быть присвоены величины с плавающей запятой. Объявление перечисления Синтаксис enum tag enum list identifier , identifier enum tag identifier , identifier Объявление перечисления задает имя переменной перечисления и определяет список именованных констант, называемый списком перечисления. Значением каждого имени списка является целое число.
Переменная перечисления принимает значение одной из именованных констант списка. Именованные константы списка имеют тип int. Таким образом, память соответствующая переменной перечисления это память, необходимая для размещения отдельной целой величины. Объявление перечисления начинается с ключевого слова enum и имеет две формы представления. В первой форме представления имена перечисления задаются в списке перечисления enum list.
Опция tag это идентификатор, который именует тип перечисления, определенного в enum list. Переменную перечисления именует identifier. В объявлении может быть описана более чем одна переменная перечисления. Во второй форме используется тег перечисления, который ссылается на тип перечисления. В этой форме объявления список перечисления не представлен, поскольку тип перечисления определен в другом месте. Если задаваемый тег не ссылается на уже определенный тип перечисления, или если именуемый
тегом тип находится вне текущей видимости, то выдается ошибка. Язык программирования Си 35 enum list имеет следующий синтаксис identifier constant expression , identifier constant expression Каждый идентификатор именует элементы перечисления. По умолчанию первому идентификатору соответствует значение 0, следующий идентификатор ассоциируется со значением 1 и т.д. Имя константы перечисления эквивалентно ее значению.
Запись constant expression переопределяет последовательность значений, заданных по умолчанию. Идентификатор, следующий перед записью constant expression принимает значение, задаваемое этим константным выражением. Константное выражение имеет тип int и может быть отрицательным. Следующий идентификатор в списке ассоциируется с величиной, равной constant expression 1, если он явно не задается другой величиной. Перечисление может содержать повторяющиеся значения идентификаторов, но
каждый идентификатор должен быть уникальным. Кроме того, он должен быть отличным от всех других идентификаторов перечислений с той же видимостью. Например, двум различным идентификаторам null и zero может быть задано значение 0 в одном и том же перечислении. Идентификаторы должны быть отличны от других идентификаторов с той же самой видимостью, включая имена обычных переменных и идентификаторы других перечислений. Теги перечислений должны быть отличны от тегов перечислений, тегов структур и совмещений с той же самой
видимостью. Примеры Example 1 enum day saturday, sunday 0, monday, tuesday, wednesday, thursday, friday Язык программирования Си 36 workday Example 2 enum day today wednesday В первом примере определяется тип перечисления, поименованный day и объявляется переменная workday этого типа перечисления. С saturday по умолчанию ассоциируется значение 0. Идентификатор sunday явно устанавливается в 0. Оставшиеся идентификаторы по умолчанию принимают значение
от 1 до 5. Во втором примере переменной today типа enum day присваивается значение из перечисления. Заметим, что для присваивания используется имя константы из перечисления. Так как тип перечисления day был предварительно объявлен, то достаточно сослаться только на тег перечисления. Объявления структур Синтаксис struct tag member declaration list declarator , declarator struct tag declarator , declarator Объявление структуры задает имя типа структуры и специфицирует последовательность
переменных величин, называемых элементами структуры, которые могут иметь различные типы. Объявление структуры начинается с ключевого слова struct и имеет две формы представления, как показано выше. В первой форме представления типы и имена элементов структуры специфицируются в списке объявлений элементов member declaration list . tag это идентификатор, который именует тип структуры, определенный в списке объявлений элементов. Каждый declarator задает имя переменной типа структуры.
Тип переменной в деклараторе может быть модифицирован на указатель к структуре, на массив структур или на функцию, возвращающую структуру. Вторая синтаксическаяформа использует тег tag структуры для ссылки на тип структуры. В этой форме объявления отсутствует список объявлений элементов, поскольку тип структуры определен в другом месте. Определение типа структуры должно быть видимым для тега, который используется Язык программирования Си 37 в объявлении и определение должно предшествовать объявлению
через тег, если тег не используется для объявления указателя или структурного типа typedef. В последних случаях объявления могут использовать тег структуры без предварительного определения типа структуры, но все же определение должно находиться в пределах видимости объявления. Список объявлений элементов member declaration list это одно или более объявлений переменных или битовых полей. Каждая переменная, объявленная в этом списке, называется элементом структурного типа.
Объявления переменных списка имеют тот же самый синтаксис, что и объявления переменных, за исключением того, что объявления не могут содержать спецификаторов класса памяти или инициализаторов. Элементы структуры могут быть любого типа основного, массивом, указателем, совмещением или структурой. Элемент не может иметь тип структуры, в которой он появляется. Однако, элемент может быть объявлен, как указатель на тип структуры, в которую он входит, позволяя
создавать списочные структуры. Битовые поля Объявления битовых полей имеют следующий синтаксис type specifier identifier constant expression Битовое поле состоит из некоторого числа бит, специфицированных константным выражением constant expression . Для битового поля спецификатор типа type specifier должен специфицировать беззнаковый целый тип, а константное выражение должно быть неотрицательной целой величиной. Массивы битовых полей, указатели на битовые поля и функции, возвращающие битовые поля не допускаются.
Идентификатор identifier именует битовое поле. Неименованное битовое поле, чей размер специфицируется как нулевой, имеет специальное назначение оно гарантирует, что память для следующей переменной объявления будет начинаться на границе int. Идентификаторы элементов внутри объявляемой структуры должны быть уникальными. Идентификаторы элементов внутри разных структур могутсовпадать. В пределах той же самой Язык программирования Си 38 видимости теги структур должны отличаться от других
тегов тегов других структур, совмещений и перечислений . Переменные элементы структуры запоминаются последовательно в том же самом порядке, в котором они объявляются первой переменной соответствует самый младший адрес памяти, а последней самый старший. Память каждой переменной начинается на границе свойственной ее типу. Поэтому могут появляться неименованные участки между соседними элементами.
Битовые поля не располагаются на пересечении границ, объявленных для них типов. Например, битовое поле, объявленное с типом unsigned int, упаковывается или в пространстве, оставшимся от предыдущего unsigned int или начиная с нового unsigned int. Примеры Example 1 struct float x,y complex Example 2 struct employee char name 20 int id long class temp Example 3 struct employee student, faculty, staff
Example 4 struct sample char c float pf struct sample next x Example 5 struct unsigned icon 8 unsigned color 4 unsigned underline 1 unsigned blink 1 screen 25 80 Язык программирования Си 39 В первом примере объявляется переменная с именем complex типа структура. Эта структура состоит из двух элементов x и y типа float. Тип структуры не поименован. Во втором примере объявляется переменная с именем temp типа структура.
Структура состоит из трех элементов с именами name, id и class. Элемент с именем name это массив из 20 ти элементов типа char. Элементы с именами id и class это простые переменные типа int и long соответственно. Идентификатор employee является тегом структуры. В третьем примере объявлены три переменных типа структура с именами student, faculty и staff. Каждая из структур состоит из трех элементов одной и той же конструкции.
Элементы определены при объявлении типа структуры с тегом employee в предыдущем примере. В четвертом примере объявляется переменная с именем x типа структура. Первые два элемента структуры представлены переменной c типа char и указателем pf на величину типа float. Третий элемент с именем next объявляются как указатель на описываемую структуру sample. В пятом примере объявляется двумерный массив поименованный screen, элементы которого имеют структурный
тип. Массив состоит из 2000 элементов и каждый элемент это отдельная структура, состоящая из четырех элементов типа bit fild с именами icon, color, underline и blink. Объявление совмещений Синтаксис union tag member declaration list declarator , declarator union tag declarator , declarator Объявление совмещения определяет имя переменной совмещения и специфицирует множество переменных, называемых элементами совмещения, которые могут быть различных типов.
Переменная с типом совмещения запоминает любую отдельную величину, определяемую набором элементов совмещения. Язык программирования Си 40 Объявление совмещения имеет тот же самый синтаксис, как и объявление структуры, за исключением того, что она начинается с ключевого слова union вместо ключевого слова struct. Для объявления совмещения и структуры действуют одни и те же правила, за исключением того, что в совмещении не допускаются элементы типа битовых полей. Память, которая соответствует переменной типа совмещение,
определяется величиной для размещения любого отдельного элемента совмещения. Когда используется наименьший элемент совмещения, то переменная типа совмещения может содержать неиспользованное пространство. Все элементы совмещения запоминаются в одном и том же пространстве памяти переменной, начиная с одного и того же адреса. Запомненные значения затираются каждый раз, когда присваивается значение очередного элемента совмещения. Объявление массива
Синтаксис type specifier declarator constant expression type specifier declarator Здесь квадратные скобки это терминальные символы. Объявление массива определяет тип массива и тип каждого элемента. Оно может определять также число элементов в массиве. Переменная типа массив рассматривается как указатель на элементы массива. Объявление массива может представляться в двух синтаксических формах, указанных выше.
Декларатор declarator задает имя переменной. Квадратные скобки, следующие за декларатором, модифицируют декларатор на тип массива. Константное выражение constant expression , заключенное в квадратные скобки, определяет число элементов в массиве. Каждый элемент имеет тип, задаваемый спецификатором типа type specifier , который может специфицировать любой тип, исключая void и тип функции. Во второй синтаксической форме опущено константное выражение в квадратных скобках.
Эта форма может быть использована только тогда, когда массив инициализируется или объявлен как формальный параметр или объявлен как ссылка на массив, явно определенныйгде то в программе. Язык программирования Си 41 Массив массивов или многомерный массив определяется путем задания списка константных выражений в квадратных скобках, следующего за декларатором type specifier declarator constant expression constant expression Каждое константное выражение constant expression в квадратных скобках
определяет число элементов в данном измерении массива, так что объявление двумерного массива содержит два константных выражения, трехмерного три и т.д. Если многомерный массив объявляется внутри функции или если он инициализируется либо объявляется как формальный параметр или объявляется как ссылка на массив, явно определенный где то в программе, то первое константное выражение может быть опущено. Массив указателей на величины заданного типа может быть определен посредством составного декларатора.
Типу массив соответствует память, которая требуется для размещения всех его элементов. Элементы массива с первого до последнего запоминаются в последовательных возрастающих адресах памяти. Между элементами массива в памяти разрывы отсутствуют. Элементы массива запоминаются друг за другом построчно. Например, массив, содержащий две строки с тремя столбцами каждая, char
A 2 3 будет запомнен следующим образом. Сначала запоминаются три столбца первой строки, затем элементы трех столбцов второй строки. Смысл этого в том, чтобы последний индекс был более быстрым. Чтобы сослаться на отдельный элемент массива, нужно использовать индексное выражение. Объявление указателей Синтаксис type specifier declarator Объявление указателя определяет имя переменной типа указатель и тип объекта, на который указывает эта
переменная. Декларатор declarator определяет имя переменной с возможной модификацией ее типа. Спецификатор типа type specifier задает тип объекта, который может быть базового типа, типа структуры или совмещения. Язык программирования Си 42 Переменная типа указатель может указывать также на функции, массивы и другие указатели. Если указатель не используется до определения типа структуры или совмещения, то он может быть объявлен ранее этого определения.
Такие объявления допускаются, поскольку компилятору не требуется знать размер структуры или совмещения, чтобы распределить память под переменную типа указатель. Указатель может быть объявлен посредством использования тега структуры или совмещения. Переменная, объявленная как указатель, хранит адрес памяти. Размер памяти, требуемый для адреса, и смысл адреса зависит от данной конфигурации машины.
Указатели на различные типы не обязательно имеют одну и ту же длину. Для некоторых реализаций используются специальные ключевые слова near, far и huge, чтобы модифицировать размер указателя. Как объявляются функции Синтаксис type specifier declarator arg type list , declarator Объявление функции определяет имя, тип возврата функции и, возможно, типы и число ее аргументов. Объявление функции также называется forward объявлением.
Декларатор функции объявляет имя функции, а спецификатор типа задает тип возврата. Если спецификатор типа опущен в объявлении функции, то предполагается, что функция возвращает величину типа int. Объявление функции может включать спецификаторы класса памяти extern или static. Список типов аргументов Список типов аргументов arg type list определяет число и типы аргументов функции. Синтаксис списка аргументов следующий type name list ,
Список имен типов это список из одного или более имен типов. Каждое имя типа отделяется от другого запятой. Первое имя типа задает тип первого аргумента, второе имя типа задает Язык программирования Си 43 тип второго аргумента и т. д. Если список имен типов заканчивается запятой с многоточием то это означает, что число аргументов функции переменно. Однако, предполагается, что функция будет иметь не меньше аргументов, чем имен типов, предшествующих
многоточию. Если список типов аргументов arg type list содержит только многоточие, то число аргументов функции является переменным или равно нулю. Важно Чтобы поддержать совместимость с программами предыдущих версий, компилятор допускает символ запятой без многоточия в конце списка типов аргументов для обозначения их переменного числа. Запятая может быть использована и вместо многоточия для объявления нуля или более аргументов функции. Использование запятой поддерживается только для совместимости.
Использование многоточия рекомендуетсядля нового представления. Имя типа type name для типов структуры, совмещения или базового типа состоит из спецификатора этого типа такого как int . Имена типов для указателей, массивов и функций формируются путем комбинации спецификатора типа с абстрактным декларатором. Абстрактный декларатор это декларатор без идентификатора. Для того чтобы объявить функцию, не имеющую аргументов, может быть использовано специальное ключевое
слово void на месте списка типов аргументов. Компилятор вырабатывает предупреждающее сообщение, если в вызове такой функции будут специфицированы аргументы. Еще одна специальная конструкция допускается в списке типов аргументов. Это фраза void , которая специфицирует аргумент типа указатель. Эта фраза может быть использована в списке типов аргументов вместо имени типа.
Список типов аргументов может быть опущен. В этом случае скобки после идентификатора функции все же требуются, хотя они и пусты. В этом случае в объявлении функции не определяются ни типы, ни число аргументов в функции. Когда эта информация опускается, то компилятор не проверяет соответствия между формальными и фактическими параметрами при вызове функции. Язык программирования Си 44 Тип возврата Функции могут возвращать величины любого типа за исключением массивов и функций.
Для этого посредством спецификатора типа type specifier в объявлении функции можно специфицировать любой тип основной, структуру или совмещение. Идентификатор функции может быть модифицирован одной или несколькими звездочками , чтобы объявить возвращаемую величину типа указателя. Хотя функции и не допускают возвратов массивов или функций, но они могут возвращать указатели на массивы или функции. Функции, которые возвращают указатели на величины типа массив или функция, объявляются
посредством модификации идентификатора функции квадратными скобками, звездочкой и круглыми скобками, чтобы сформировать составной декларатор. Классы памяти Класс памяти переменной, которая определяет какой либо объект, имеет глобальное или локальное время жизни. Объект с глобальным временем жизни существует и имеет значение на протяжении всей программы. Все функции имеют глобальное время жизни. Переменные с локальным временем жизни захватывают новую память
при каждом выполнении блока, в котором они определены. Когда управление на выполнение передается из блока, то переменная теряет свое значение. Хотя Си определяет два типа классов памяти, но, тем не менее, имеется следующих четыре спецификатора классов памяти auto register static extern Объекты классов auto и register имеют локальное время жизни. Спецификаторы static и extern определяют объекты с глобальным временем жизни.
Каждый из спецификаторов класса памяти имеет определенный смысл, который влияет на видимость функций и переменных в той же мере, как и сами классы памяти. Язык программирования Си 45 Термин видимость относится к той части программы, в которой могут ссылаться друг на друга функции и переменные. Объекты с глобальным временем жизни существуют на протяжении выполнения исходной программы, но они могут быть видимы не во всех частях программы.
Месторасположение объявления переменной или функции внутри исходных файлов также влияют на класс памяти и видимость. Говорят, что объявления вне определения всех функций и переменных относятся к внешнему уровню, а объявления внутри определений функций относятся к внутреннему уровню. Точный смысл каждого спецификатора класса памяти зависит от того, находится ли объявление на внешнем или внутреннем уровне и от того, объявлен ли объект функцией или переменной.
Объявления переменной на внешнем уровне Объявления переменной на внешнем уровне используют спецификаторы класса памяти static и extern или совсем опускают их. Спецификаторы класса памяти auto и register не допускаются на внешнем уровне. Объявления переменных на внешнем уровне это определения переменных или ссылки на определения, сделанные в другом месте. Объявление внешней переменной, которое инициализирует эту переменную явно или неявно
, называется определением этой переменной. Определение на внешнем уровне может задаваться в различных формах. Переменная на внешнем уровне может быть определена путем ее объявления со спецификатором класса памяти static. Такая переменная можетбыть явно инициализирована константным выражением. Если инициализатор отсутствует, то переменная автоматически инициализируется нулем во время компиляции. Таким образом, объявления static int k 16 и static int k оба рассматриваются как определения.
Переменная определяется, когда она явно инициализируется на внешнем уровне. Например, int j 3 это определение переменной. Язык программирования Си 46 Так как переменная определяется на внешнем уровне, то она видима в пределах остатка исходного файла, от места, где она определена. Переменная не видима выше своего определения в том же самом исходном файле ни в других исходных файлах программы, если не объявлена ссылка, которая делает ее видимой.
Переменная может быть определена на внешнем уровне внутри исходного файла только один раз. Если задается спецификатор класса памяти static, то в других исходных файлах могут быть определены переменные с тем же именем. Так как каждое определение static видимо только в пределах своего собственного исходного файла, то конфликта не возникнет. Спецификатор класса памяти extern используется для объявления ссылки на переменную, определенную где то в другом месте.
Такие объявления используются в случае, когда нужно сделать видимым определение переменной в других исходных файлах или выше места, где она определена в том же самом исходном файле. Так как ссылка на переменную объявлена на внешнем уровне, то переменная видима в пределах остатка исходного файла от места объявления ссылки. В объявлениях, которые используют спецификатор класса памяти extern, инициализация не допускается, так как они ссылаются на переменные, чьи величины уже определены.
Переменная, на которую делается ссылка extern, должна быть определена на внешнем уровне только один раз. Определение может быть сделано в любом из исходных файлов, составляющих программу. Есть одно исключение из правил, описанных выше. Можно опустить из объявления переменной на внешнем уровне спецификатор класса памяти и инициализатор. Например, объявление int n будет правильным внешним объявлением.
Это объявление имеет два различных смысла в зависимости от контекста. 1. Если где нибудь в программебудет определена на внешнем уровне переменная с тем же именем, то объявление является ссылкой на эту переменную, как если бы был использован спецификатор класса памяти extern в объявлении. Язык программирования Си 47 2. Если нет такого определения, то объявленной переменной распределяется память во время линкования и переменная инициализируется нулем.
Если в программе появится более чем одно такое объявление, то память распределится для наибольшего размера из объявленных переменных. Например, если программа содержит два неинициализированных объявления переменной i на внешнем уровне int i и char i то память во время линкования распределится под переменную i типа int. Неинициализированные объявления переменной на внешнем уровне не рекомендуются для файлов, которые могут быть размещены в библиотеку. Пример
SOURCE FILE ONE extern int i reference to i defined below main i printf d n , i i equals 4 next int i 3 definition of i next i printf d n , i i equals 5 other SOURCE FILE TWO extern int i reference to i in first source file other i printf d n , i i equals 6 Язык программирования Си 48 Объявление переменной на внутреннем уровне Любой из четырех спецификаторов класса памяти может быть использован для объявления переменной на внутреннем
уровне. Если спецификатор класса памяти опускается в объявлении переменной на внутреннем уровне, то подразумевается класс памяти auto. Спецификатор класса памяти auto объявляет переменную с локальным временем жизни. Переменная видима только в том блоке, где она объявлена. Объявления переменных auto могут включать инициализаторы. Переменные класса памяти auto автоматически не инициализируются, а инициализируются явно при объявлении
или присваивании начальных значений, посредством операторов внутри блока. Если нет инициализации, то величина переменной auto считается неопределенной. Спецификатор класса памяти register сообщает компилятору о том, чтобы он распределил память под переменную в регистре, если это возможно. Использование регистровой памяти обычно приводит к более быстрому времени доступа и к меньшему размеру результирующего кода.
Переменные, объявленные с классом памяти register имеют ту же самую видимость, что и переменные auto. Число регистров, которое может быть использовано под память переменных, зависит от машины. Когда компилятор встречает спецификатор класса памяти register в объявлении, а свободного регистра не имеется, то для переменной распределяется память класса auto. Компилятор назначает переменным регистровую память в том порядке, в котором появляются объявления в
исходном файле. Регистровая память, если она имеется, гарантирована только для целого и адресного типов. Переменная, объявленная на внутреннем уровне со спецификатором класса памяти static, имеет глобальное время жизни и имеет видимость только внутри блока, в котором она объявлена. В отличие от переменных auto, переменные, объявленные как static, сохраняют свое значение при завершении блока. Переменные класса памяти static могут быть инициализированы константным выражением.
Если явной инициализации нет, то переменная класса памяти static Язык программирования Си 49 автоматически устанавливается в 0. Инициализация выполняется один раз во время компиляции. Инициализация переменной класса памяти static не повторяется при новом входе в блок. Переменная, объявленная со спецификатором класса памяти extern, является ссылкой на переменную с тем
же самым именем, определенную на внешнем уровне в любом исходном файле программы. Цель внутреннего объявления extern состоит в том, чтобы сделать определение переменной внешнего уровня видимой внутри блока. Внутреннее объявление extern не изменяет видимость глобальной переменной в любой другой части программы. Пример int i 1 main reference to i, defined above extern int i initial value is zero a is visible only within main static int a b is stored in a register, if possible register int
b 0 default storage class is auto int c 0 values printed are 1, 0, 0, 0 printf d n d n d n d n , i, a, b, c other other i is redefined int i 16 this a is visible only within other static int a 2 a 2 values printed are 16, 4 printf d n d n , i, a Переменная i определяется на внешнем уровне с инициализацией 1. В функции main объявлена ссылка extern на Язык программирования Си 50 переменную i внешнего уровня. Переменная класса памяти static автоматически устанавливается в 0,
так как инициализатор опущен. Вызов функции print предполагается, что функция print определена в каком то месте исходной программы печатает величины 1, 0, 0, 0. В функции other, переменная i переопределяется как локальная переменная с начальным значением 16. Это не влияет на значение внешней переменной i. Переменная a объявляется как переменная класса памяти static с начальным значением 2. Она не противоречитпеременной a, объявленной в функции main, так как
видимость переменных класса памяти static на внутреннем уровне ограничена блоком, в котором она объявлена. Объявление функции на внешнем и внутреннем уровнях Функции могут быть объявлены со спецификаторами класса памяти static или extern. Функции всегда имеют глобальное время жизни. Правила видимости для функций отличаются от правил видимости для переменных. Объявления функций на внутреннем уровне имеют тот же самый смысл, что и объявления на
внешнем уровне. Это значит, что функции не могут иметь блочной видимости и видимость функций не может быть вложенной. Функция объявленная как static, видима только в пределах исходного файла, в котором она определяется. Любая функция в том же самом исходном файле может вызвать функцию static, но функции static из других файлов нет. Функция static с тем же самым именем может быть объявлена в другом исходном файле. Функции, объявленные как extern видимы в пределах всех исходных файлов, которые составляют программу.
Любая функция может вызвать функцию extern. Объявления функций, в которых опущен спецификатор класса памяти, считаются по умолчанию extern. Инициализация В объявлении переменной может быть присвоено начальное значение посредством инициализатора. Величина или величины инициализатора присваиваются переменной. Синтаксически записи инициализатора предшествует знак
Язык программирования Си 51 равно initializer Могут быть инициализированы переменные любого типа. Функции не инициализируются. Объявления, которые используют спецификатор класса памяти extern не могут содержать инициализатора. Переменные, объявленные на внешнем уровне, могут быть инициализированы. Если они явно не инициализированы, то они устанавливаются в нуль во время компиляции или линкования. Любая переменная, объявленная со спецификатором класса памяти static, может быть инициализирована константным
выражением. Инициализация переменных класса static выполняется один раз во время компиляции. Если отсутствует явная инициализация, то переменные класса памяти static автоматически устанавливаются в нуль. Инициализация переменных auto и register выполняется каждый раз при входе в блок, в котором они объявлены. Если инициализатор опущен в объявлении переменной класса памяти auto или register, то начальное значение переменной не определено. Инициализация составных типов auto массив, структура, совмещение
запрещена. Любое составное объявление класса памяти static может быть инициализировано на внешнем уровне. Начальными значениями для внешних объявлений переменной и для всех переменных static как внешних так и внутренних должно быть константное выражение. Автоматические и регистровые переменные могут быть инициализированы константными или переменными величинами. Базовые типы и типы указателей Синтаксис expression Величина выражения присваивается переменной.
Для выражения допустимы правила преобразования. Язык программирования Си 52 Составные типы Синтаксис initializer list Список инициализаторов initializer list это последовательность инициализаторов, разделенных запятыми. Каждый инициализатор в последовательности это либо константное выражение, либо список инициализаторов. Поэтому, заключенный в фигурные скобки список, может появиться внутри другого списка инициализации. Эта конструкция используется для инициализации элементов составных
конструкций. Для каждого списка инициализации значения константных выражений присваиваются в порядке следования элементов составной переменной. Когда инициализируется совмещение, то список инициализаторов представляет собой единственное константное выражение. Величина константного выражения присваивается первому элементу совмещения. Если в списке инициализации меньше величин, чем их имеется в составном типе, то оставшиеся памяти инициализируются
нулем. Если число инициализирующих величин больше чем требуется, то выдается ошибка. Эти правила применяются к каждому вложенному списку инициализаторов, точно так же как и ко всей конструкции в целом. Эти дополнительные запятые допускаются, но не требуются. Требуются только те запятые, которые разделяют константные выражения и списки инициализации. Если список инициализаторов не структурирован под составной объект, то его величины присваиваютсяв
том порядке, в котором подстыкованы элементы объекта. Фигурные скобки могут также появляться вокруг индивидуальных инициализаторов в списке. Когда инициализируются составные переменные, то нужно позаботиться о том, чтобы правильно использовать фигурные скобки и списки инициализаторов. В следующем примере иллюстрируется более детально интерпретация компилятором фигурных скобок. Язык программирования
Си 53 Строковые инициализаторы Массив может быть инициализирован строчным литералом. Например, char code abc инициализирует code как массив символов из четырех элементов. Четвертым элементом является символ 0, который завершает все строковые литералы. Если специфицируется размер массива, а строка больше чем специфицированный размер, то лишние символы отбрасываются. Следующее объявление инициализирует переменную code, как трехэлементный массив символов
char code 3 abcd В примере только три первые символа инициализатора назначаются для массива code. Символ d и символ нуль отбрасываются. Если строка короче, чем специфицированный размер массива, то оставшиеся элементы массива инициализируются нулем символом 0 . Объявления типов Объявление типа определяет имя и элементы структурного или совмещающего типов или имя и перечислимое множество перечислимого типа. Имя типа может быть использовано в объявлениях переменных
и функций в качестве ссылки на этот тип. Это полезно, когда многие переменные или функции имеют один и тот же тип. Объявление typedef определяет спецификатор типа для типа. Это объявление используется для того, чтобы создавать более короткие или более осмысленные имена типов уже определенных в Си или объявленных пользователем. Типы структур, совмещений и перечислений Объявления типов структур, совмещений и перечислений имеют
ту же самую общую синтаксическую форму, как и объявления переменных этих типов. В объявлении типа идентификатор переменной опущен, так как нет переменной Язык программирования Си 54 которая объявляется. Именем структуры, совмещения или перечисления является тег. В объявлении типа может появиться список объявлений элементов member declaration list или список перечисления enum list , определяющие тип. Сокращенная форма объявления переменной, в котором tag ссылается
на тип, определенный где то еще, при объявлении типа не используется. Объявления typedef Синтаксис typedef type spesifier declarator , declarator Объявления typedef являются аналогом объявления переменной, за исключением того, что ключевое слово typedef заменяет спецификатор класса памяти. Объявление интерпретируется тем же самым путем, как объявления переменной или функции, но declarator вместо того, чтобы стать переменной типа, специфицированного объявлением,
становится синонимом имени типа. Объявление typedef не создает типов. Оно создает синонимы для существующих имен типов, которые были специфицированы другим способом. Любой тип может быть объявлен с typedef, включая типы указателя, функции и массива. Имя с ключевым словом typedef для типов указателя, структуры или совмещения может быть объявлено прежде чем эти типы будут определены, но в пределах видимости объявления.
Имена типов Имя типа специфицирует особенности типа данных. Имена типов используются в трех контекстах в списках типов аргументов, при объявлении функций, в вычислениях cast преобразованиях типов , и в sizeof операциях. Именами для основных, перечисляющих, структурных и совмещающих типов являются спецификаторы типа для каждого из них. Имена для типов указателя, массива и функции задаются следующей синтаксической формой
type specifier abstract declarator Язык программирования Си 55 Абстрактный декларатор abstract declarator это декларатор без идентификатора, состоящий из одного или более модификаторов указателей, массивов и функций. Модификатор указателя всегда появляется перед идентификатором в деклараторе, в то время как модификатор массива или функции появляются после идентификатора.
Таким образом, чтобы правильно интерпретировать абстрактный декларатор, нужно начинать интерпретацию с подразумеваемого идентификатора. Абстрактные деклараторы могут быть составными. Скобки в составном абстрактном деклараторе специфицируют порядок интерпретации, подобно тому как это делается при интерпретации составных деклараторов объявлений. Абстрактный декларатор, состоящий из пустых круглыхскобок не допускается, поскольку это двусмысленно.
В этом случае невозможно определить находится ли подразумеваемый идентификатор внутри скобок, и в таком случае это немодифицированный тип, или перед скобками, тогда это тип функции. Спецификаторы типа, установленные посредством объявлений typedef, также рассматриваются как имена типов. Выражения и присваивания В Си присваиваются значения выражений. Помимо простого присваивания посредством операции ,
Си поддерживает составные операции присваивания, которые перед присваиванием выполняют дополнительные операции над своими операндами. Окончательное значение результата зависит от старшинства операций и от побочных эффектов, если они возникают. Порядок вычисления устанавливается определенным группированием операндов и операций в выражении. Побочный эффект это изменения состояния машины, вызванные в процессе вычисления выражения. В выражении с побочным эффектом, вычисление одного операнда может зависеть от
значения другого. Для одних и тех же операций от порядка, в котором вычисляются операнды, также зависит результат выражения. Величина, представляемая каждым операндом в выражении, имеет тип, который может быть преобразован к другим типам в определенном контексте. Преобразования типов имеют место в Язык программирования Си 56 присваиваниях, cast операциях, вызовах функций и при выполнении операций.
Операнды Операнд в Си это константа, идентификатор, строка, вызов функции, индексное выражение, выражение выбора структурного элемента или более сложное выражение, сформированное комбинацией операндов и операций или заключением операндов в скобки. Любой операнд, который имеет константное значение, называется константным выражением. Каждый операнд имеет тип. Операнд может быть преобразован из оригинального типа к другому типу посредством операции преобразования типов. Выражение преобразования типа может быть использовано
в качестве операнда выражения. Константы Операнду константе соответствует значение и тип представляющей его константы. Константа символ имеет тип int. Целая константа имеет типы int, long, unsigned int или unsigned long, в зависимости от размера целого и от того как специфицирована его величина. Константы с плавающей точкой всегда имеют тип double. Идентификаторы Идентификаторы именуют переменные и функции.
Каждый идентификатор имеет тип, который устанавливается при его объявлении. Значение идентификатора зависит от типа следующим образом ? идентификаторы целых и плавающих типов представляют величины соответствующего типа идентификатор перечисляющего типа представляет значение одной константы из множества значений констант в перечислении. Значение идентификатора равно значению этой константы.
Тип значения есть int, что следует из определения перечисления идентификатор структурного или совмещающего типов представляет величины, специфицированные в структуре или совмещении. Язык программирования Си 57 ? идентификатор, объявленный как указатель, представляет указатель на величину специфицированного типа идентификатор, объявленный как массив, представляет указатель, чье значение является адресом первого элемента массива. Тип адресуемых указателем величин это тип элементов массива.
Например, если series объявлен как массив целых из 10 ти элементов, то идентификатор series представляет адрес массива, тогда как индексное выражение series 5 ссылается на шестой элемент массива. Адрес массива не изменяется во время выполнения программы, хотя значения отдельных элементов могут изменяться. Значение указателя, представленное идентификатором массива, не является переменной и поэтому идентификатор массива не может появляться в левой части операции присваивания идентификатор, объявленный
как функция, представляет указатель, чье значение является адресом функции. Тип, адресуемый указателем, это специфицированный тип функционального возврата. Адрес функции не изменяется во время выполнения программы. Меняется только значение возврата. Таким образом, идентификаторы функции не могут появляться в левой части операции присваивания. Строки Строковый литерал состоит из последовательности символов, заключенных
в двойные кавычки. Строковыйлитерал представляется в памяти как массив элементов типа char. Строковый литерал представляет адрес первого элемента этого массива. Адрес первого элемента строки является константой, так же как и сама строка. Так как строковые литералы это полноценные указатели, то они могут быть использованы в контексте, допускающем величины типа указателей, подчиняясь при этом тем же самым ограничениям.
Строковые литералы имеют все же одно дополнительное ограничение они не изменяемы и не могут появиться в левой части операции присваивания. Язык программирования Си 58 Последним символом строки всегда является символ нуль 0. Символ нуль не видим в строковом выражении, но он добавляется как последний элемент, когда строка запоминается. Таким образом, строка abc содержит четыре символа, а не три.
Вызовы функций Синтаксис expression expression lils Вызов функции состоит из выражения expression , за которым следует список выражений expression list . Значению выражения соответствует адрес функции например, значение идентификатора функции . Значение каждого выражения из списка выражений выражения в списке разделены запятыми соответствует фактическому аргументу функции. Список выражений может быть пустым.
Выражение вызова функции имеет значение и тип своего возврата. Если тип возврата функции void, то и выражение вызова функции имеет тип void. Если возврат из вызванной функции произошел не в результате выполнения оператора return, то значение функции не определено. Индексные выражения Синтаксис expression1 expression2 Здесь квадратные скобки это терминальные символы. Индексное выражение представляет величину, адрес которой
состоит из суммы значений выражения1 expression1 и выражения2 expression2 . Выражение1 это любой указатель, такой как идентификатор массива, а выражение2 это целочисленная величина. Выражение2 должно быть заключено в квадратные скобки . Индексное выражение обычно используется для ссылок на элементы массива, тем не менее, индекс может появиться с любым указателем. Индексное выражение вычисляется путем сложения целой величины expression2
с значением указателя expression1 c последующим применением к результату операции разадресации . Например,для одномерного массива следующие четыре Язык программирования Си 59 выражения эквивалентны в предположении, что a это указатель, а b это целое. a b a b b a b a В соответствии с правилами преобразования типов для операции сложения, целочисленная величина преобразуется к адресному представлению путем умножения ее на размер типа, адресуемого указателем.
Например, предположим, что идентификатор line ссылается на массив величин типа int. Чтобы вычислить выражение line i , целая величина i умножается на размер типа int. Преобразованное значение i представляет i позиций типа int. Это преобразованное значение складывается с начальным значением указателя line, что дает адрес, который расположен на i позиций типа int от line. Последним шагом вычисления индексного выражения является операция
разадресации, применяемая к полученному адресу. Результатом является значение элемента массива, который позиционирован. Заметим, что индексное выражение line 0 представляет значение первого элемента массива, так как отсчет смещения ведется от нуля. Следовательно, такое выражение, как line 5 , ссылается на шестой элемент массива. Ссылки на многомерный массив Индексное выражение может быть снова проиндексировано.
Синтаксис такого выражения следующий expression1 expression2 expression3 Данное индексное выражение интерпретируется слева направо. Сначала вычисляется самое левое индексное выражение expression1 expression2 . Адрес результата сложения expressin1 и expression2 имеет смысл адресного выражения, с которым складывается expression3 и т.д. Операция разадресации осуществляется после вычисления последнего индексного выражения.
Однако, операции разадресации не производится, если значение последнего указателя адресует величину типа массив. Язык программирования Си 60 Выражения с несколькими индексами ссылаются на элементы многомерных массивов. Многомерный массив это массив, элементами которого являются массивы. Например, первым элементом трехмерного массива является массив с двумя измерениями. Выражения с операциями Выражения с операциями могут быть унарными, бинарными или тернарными.
Унарное выражение состоит из операнда с предшествующей унарнойоперацией unop или операнда, заключенного в круглые скобки, с предшествующим ему ключевым словом sizeof. Синтаксис unop operand sizeof operand Бинарное выражение состоит из двух операндов, разделенных бинарной операцией binop . Синтаксис operand binop operand Тернарное выражение состоит из трех операндов, разделенных тернарной операцией ? Синтаксис operand ? operand operand
Выражения присваивания используют унарные, бинарные и составные операции присваивания. Унарными операциями присваивания являются инкремент и декремент . Бинарная операция присваивания всего одна . Составные операции присваивания будем обозначать как compound assign ops . Каждая составная операция присваивания это комбинация бинарной операции с простой операцией присваивания. Синтаксис выражений присваивания operand operand operand operand operand operand operand
compound assignment ops operand Язык программирования Си 61 Выражения в скобках Любой операнд может быть заключен в скобки. Они не влияют на тип и значение выражения, заключенного в скобки. Например, в выражении 10 5 5 скобки, заключающие запись 10 5, означают, что величина 10 5 является левым операндом операции деления. Результат выражения 10 5 5 равен 3.
Без скобок значение записи 10 5 5 равнялось бы 11. Хотя скобки влияют на то, каким путем группируются операнды в выражении, они не гарантируют детальный порядок вычисления выражения. Type!cast выражения Type cast выражения имеют следующий синтаксис type name operand Константные выражения Константное выражение это выражение, результатом вычисления которого является константа. Операндами константного выражения могут быть целые константы, константы символы,
плавающие константы, константы перечисления, type cast выражения целого и плавающего типов и другие константные выражения. Операнды могут комбинироваться и модифицироваться посредством операций. Константные выражения не могут использовать операции присваивания или бинарную операцию последовательного вычисления. Унарная операция адресации может быть использована только при некоторых инициализациях. Константные выражения, используемые в директивах препроцессора, имеют дополнительные ограничения, поэтому
называются ограниченнымиконстантными выражениями restricted constant expression Ограниченные константные выражения не могут содержать
! |
Как писать рефераты Практические рекомендации по написанию студенческих рефератов. |
! | План реферата Краткий список разделов, отражающий структура и порядок работы над будующим рефератом. |
! | Введение реферата Вводная часть работы, в которой отражается цель и обозначается список задач. |
! | Заключение реферата В заключении подводятся итоги, описывается была ли достигнута поставленная цель, каковы результаты. |
! | Оформление рефератов Методические рекомендации по грамотному оформлению работы по ГОСТ. |
→ | Виды рефератов Какими бывают рефераты по своему назначению и структуре. |