* C for Dummies * Aleph * 2000-07-31 * 005 *
-----[00]----------[Quote of Day]-----------------------------------------
ПРАВИЛА ВЫЖИВАНИЯ
- Если вы откупорили что-либо - закупорьте.
- Если в руках у вас жидкое - не разлейте, порошкообразное -
не рассыпьте, газообразное - не выпустите наружу.
- Если включили, выключите.
- Если открыли - закройте.
- Если разобрали - соберите.
- Если вы не можете собрать - позовите на помощь умельца.
- Если не вы разбирали - не вздумайте собирать.
- Если вы одолжили что-либо - верните.
- Если вы чем-то пользуетесь - держите в чистоте и порядке.
- Если вы привели что-либо в беспорядок - восстановите статус-кво.
- Если вы сдвинули что-то - верните на место.
- Если вы хотите воспользоваться чем-либо, принадлежащим другому,
попросите разрешения.
- Если вы не знаете, как это действует, ради Бога не трогайте.
- Если это вас не касается - не вмешивайтесь.
- Если не знаете, как это делается, сразу спросите.
- Если не можете что-либо понять - почешите в затылке.
- Если все же не поймете, то и не пытайтесь.
- Если вы горите на работе, постарайтесь, чтобы у вас ничего не
загоралось.
- Если у вас что-либо взорвалось, проверьте: остались ли вы живы.
- Если не усвоили этих правил, не входите в лабораторию!
Джайпурский университет [Индия]
Химия и Жизнь #1,90
Чл.Корр. АН СССР М.Г.Воронков
-----[01]----------[Hot News]---------------------------------------------
1. Э. Дейкстра "Дисциплина программирования".
http://members.xoom.com/c4dummies/files/dijkstra.zip (383,027)
Какому-то умнику пришло в голову закатать это в PDF, так что извлечь
оттуда текст назад можно разве что FineReader'ом.
2. Начиная с этого выпуска, рассылка будет дублироваться (только текстовый
вариант) с сервера www.egroups.com
Подписка: c4d-subscribe@egroups.com
-----[02]----------[Topic]------------------------------------------------
Трансляция. Состав среды Turbo C 2.0. Описание языка С. Ключевые
(резервированные) слова. Идентификаторы. Константы (литералы). Операторы.
-----[03]----------[Body]-------------------------------------------------
Трансляция
----------
Со времени первого выпуска прошел почти месяц и я полагаю, Вы уже
обзавелись компилятором С и горите желанием узнать, а для чего он вообще
нужен и почему недостаточно просто написать программу на С на бумажке и
засунуть ее в какую-нибудь щель в компьютере.
Итак, для чего все эти сложности?
На самом деле, единственный язык, который "понимает" компьютер - это язык
команд его собственного процессора, то есть, в типичном случае, что-то
порядка пары сотен простых арифметических и логических операций.
Для выполнения чего-то более сложного, необходимо это "сложное" разбить на
отдельные шаги, понятные компьютеру. Если такое разбиение невозможно, то
компьютер Вам не поможет. Иными словами, решаемы только задачи, в конечном
счете сводимые к простым манипуляциям с целыми числами.
Учитывая распространенность компьютеров в современном мире, можете оценить,
как много таких задач: от управления космическим кораблем до игры в
шахматы. С другой стороны, несмотря на восторженный оптимизм 60-х годов,
многие задачи искусственного интеллекта, такие как создание стихов или
автоматический перевод, все еще в зачаточном состоянии.
Предположим, однако, что Ваша проблема из легко формализуемой области и
может быть выражена на языке чисел. Тогда дело за малым - сесть и
закодировать ее на языке команд того процессора, который Вы собрались
использовать.
Не верите ?
Напрасно. Первые компьютеры именно так и работали: "программа" набиралась
с помощью переключателей на пульте и, весело пощелкивая реле, компьютер
приступал к исполнению.
В усовершенствованных моделях программа записывалась на перфоленту или
перфокарты, а в остальном ничего не менялось.
Очень скоро стала ясно, что программировать в двоичных кодах, занятие
довольно-таки утомительное и были разработаны символические обозначения:
например, команда сложения обозначалась набором символов ADD, а умножения
- MUL. Перевод же символических обозначений в двоичные коды был поручен
самому компьютеру - так появились автокоды. По мере накопления опыта они
совершенствовались, появлялись символические обозначения для констант и
переменных и автокоды превратились в ассемблеры и даже кросс-ассемблеры,
когда на одном компьютере можно было создавать код для другого, с отличной
системой команд.
В это время зародилась дерзкая мысль, заставить компьютер понимать
английский язык, разумеется, достаточно упрощенный.
Этот революционный шаг был сделан фирмой IBM. В 1957 году было объявлено о
разработке под руководством Бэкуса (John W. Backus) алгоритмического языка
для численных расчетов. Соответственно и сам язык получил название FORTRAN
(Formula Translation).
Это был действительно шедевр. Даже сейчас, через 40+ лет, несмотря на
появление С, с небольшими модификациями стандарта (структуры, динамическое
выделение памяти, рекурсия), Fortran все еще (и с успехом) используется по
назначению, как самый эффективный язык для численных расчетов.
Какой бы современный процедурный язык программирования Вы не взяли, Вы
обнаружите в нем неуничтожимое влияние Fortran'а.
Как и в любом языке, основой предложения языка программирования является
глагол, определяющий выполняемое действие, другие члены его уточняют и
дополняют.
Хочу, кстати, заметить, что важнейшее качество программиста - умение
четко и связно выражать свои мысли, превосходное владение родным
языком. Если Вы не можете сделать это на своем родном языке, как можете
ожидать, что это удастся сделать на каком-то другом ?
Будучи профессиональным программистом (то есть человеком, который пишет
программы за деньги) и переписав заново километры грязного запутанного и
глючного кода, я непоколебимо уверен в справедливости этого правила.
Well.
Вам удалось написать программу на хорошем понятном компьютеру языке и Вы
горите желанием проверить ее в работе. Что Вам для этого требуется ?
Транслятор.
Транслятор (переводчик) - это программа, которая транслирует (переводит)
написанный Вами код в тот код, который будет понятен процессору данного
компьютера.
Чтобы сделать это возможным, Ваша программа должна быть записана по
определенным правилам, в соответствии со стандартом языка программирования
и не содержать слишком грубых синтаксических ошибок - так, чтобы
транслятор все еще мог понять Вас.
Обычно, процесс трансляции разбивается на несколько этапов (фаз), не все
из которых обязательны в трансляторах с различных языков.
Как правило, различают следующие этапы:
- Препроцессорная обработка
- Трансляция
- Сборка
- Постпроцессорная обработка
Препроцессорная обработка
-------------------------
Обычно, препроцессор - это крайне примитивный транслятор (иногда, в виде
отдельной программы), выполняющий некоторые простые действия над исходным
текстом: удаление пробелов и символов новой строки, удаление комментариев
и другие подобные операции, не требующие анализа кода. Кроме того,
препроцессору поручают и выполнение таких действий, как вставка кода из
других файлов и выполнение операции "поиск с заменой".
Трансляция
----------
Это основной и самый трудный этап, на котором производится сначала
синтаксический контроль (формальная правильность написания кода),
а затем его перевод в некоторый промежуточный (объектный) код.
Объектный код очень близок к исполняемому коду (командам процессора), но
все еще не может быть выполнен, так как отсутствуют адреса процедур и не
подключены системные модули.
Практически вся работа и диагностика выполняются на этом этапе.
Сборка
------
Сборка ("линковка") очень быстрая операция, которая в простейших случаях
объединяется с трансляцией. Так, например, сделано в Turbo Pascal.
Точнее сказать, в сложных проектах линкование насильно вычленяется из
трансляции по соображениям эффективности: перетрансляция одного из модулей
не влияет на остальные и сборку всего проекта. В большинстве случаев,
линкование - финишная операция, после которой получают исполняемый модуль.
На этапе линкования происходит подстановка адресов вместо символических
имен, подключаются системные модули (стартовый код, библиотеки стандартных
функций итд.), собираются в один исполняемый файл все модули проекта.
Постпроцессорная обработка
--------------------------
В каком-то смысле аналогична препроцессорной, только наоборот. Обычно
возникает из необходимости "приспособить" уже существующий транслятор под
какие-то специальные нужды. Например, выходной код будет использован для
станка с числовым программным управлением.
Вполне возможно, что Вам никогда не придется столкнуться с
постпроцессорами.
В зависимости от способа разбора программы, трансляторы делятся на два
класса: интерпретирующие (анализирующие и исполняющие программу
"построчно") и компилирующие (просматривающие и исполняющие программу
"одним куском"). Интерпретаторы проще и дешевле в разработке, компиляторы
эффективнее в смысле размеров и времени исполнения кода. Понятно, что "в
чистом виде" и те и другие встречаются редко. Интерпретаторы, обычно,
оптимизированы и создают частично прекомпилированный код, а компиляторы,
чтобы избежать многопроходной трансляции, выставляют ограничения,
характерные именно для интерпретаторов.
Состав среды Turbo C 2.0
------------------------
В дальнейшем я буду предполагать, что Вы уже инсталлировали Turbo C 2.0 с
установками по умолчанию и все файлы находятся в каталоге C:\TC и
соответствующих подкаталогах.
Схема классическая: Препроцессор - Компилятор - Линкер
В директории C:\TC Вы можете найти следующие исполняемые файлы:
TC.EXE - Интегрированная оболочка Turbo C 2.0
TCC.EXE - Собственно компилятор С, работающий из командной строки
TLINK.EXE - Линкер
CPP.EXE - Препроцессор. На самом деле, компилятор использует
другой (встроенный) препроцессор, но фирма Borland
поставляет его также и в виде отдельной утилиты для
использования при отладке.
Из оставшихся файлов я пока упомяну только два:
GREP.COM - GREP (Get Regular ExPression) - Unix-Like Утилита для
поиска с использованием регулярных выражений.
THELP.COM - Резидентный Help, вызываемый по нажатию клавиши {5}
на цифровой клавиатуре.
Описание языка С
----------------
То что будет описано ниже, несколько отличается (в лучшую сторону) от
стандарта языка С (ANSI C) и, таким образом, не вполне совместимо с
другими компиляторами С. В частности, MSC не поддерживает некоторые
удобные возможности, имеющиеся в Turbo C. Тем не менее, отличия невелики и
Вам окажется полезной почти любая книга или справочник по С.
Предложения (операторы) языка С строятся из набора базовых элементов.
В него входят:
- Ключевые (резервированные) слова
- Идентификаторы
- Константы (литералы)
- Операторы
- Разделители
Кроме того, допускаются комментарии, которые не входят в набор и не
обрабатываются компилятором. (Как мы уже говорили, они удаляются
препроцессором).
Ключевые (резервированные) слова
--------------------------------
Вот список (почти) всех зарезервированных слов, взятый из Turbo Help
KEYWORDS
asm extern return
auto far short
break float signed
case for sizeof
cdecl goto static
char huge struct
const if switch
continue int typedef
default interrupt union
do long unsigned
double near void
else pascal volatile
enum register while
Смысл и употребление этих слов фиксированы и они не могут быть употреблены
ни в каком ином контексте. Конкретно об отдельных словах мы поговорим
позднее. Обратите внимание, как мало (меньше полусотни) этих слов.
С - очень простой и компактный язык, с несложной структурой и легкими
правилами, очень удобный для изучения.
Идентификаторы
--------------
Идентификатор - это имя. Идентификатор может состоять из латинских букв,
цифр, знака '_' (underline), который тоже считается буквой и обязательно
начинаться с буквы. Прописные и строчные буквы считаются различными.
Таким образом, ALEPH, Aleph и aleph - это три разных идентификатора.
Максимальная длина идентификатора - 32 символа.
Поскольку компилятор языка С добавляет префикс '_' (underline) к
глобальным идентификаторам при трансляции, не рекомендуется начинать Ваши
собственные идентификаторы с этого символа. Позднее мы увидим, когда
безопасно игнорировать это правило.
Несколько примеров допустимых в языке С идентификаторов:
Y2K , y2k, Year_2000, XX_Century_Fox, Colambia_Pictures
Peter_I, Catherine_II, Napoleon_III, George_IV
или, даже, CHARLES_LOUIs_NAPOLEON_BONAPARTE
А вот идентификатор 20_Century_Fox недопустим.
Идентификатор SOPHIE_FRIEDERIKE_AUGUSTE_PRINZESSIN_VON_ANHALT_ZERBST хотя
и не начинается с цифры, но нарушает ограничение на максимальную длину в 32
символа.
Правило очень просто для запоминания:
Числа всегда начинаются с цифры,
Имена всегда начинаются с буквы.
Как выбирать имена (идентификаторы) ?
Я придерживаюсь принципа минимакса:
Имя должно быть настолько длинным, насколько необходимо
и настолько коротким, насколько возможно.
Константы (литералы)
--------------------
Литералы - это именно то, что следует из их названия - понимаемые
буквально, обозначающие сами себя, константные идентификаторы.
Литералы подразделяются на целочисленные, с плавающей точкой, символьные и
строковые.
Целочисленные литералы бывают трех типов:
- восьмеричные
- десятичные
- шестнадцатеричные
Должен сказать, что восьмеричные литералы за 10+ лет программирования на
С/С++ мне ни разу не встретились - это архаизм, сохранившийся со времен
первых версий языка С и машин с короткой разрядной сеткой.
Практически всегда, Вы будете иметь дело только с десятичными и
шестнадцатеричными константами.
Как это легко понять из названия, речь идет о целых числах, записанных в
системе счисления по основанию 8, 10 или 16.
Восьмеричные литералы состоят из восьмеричных (от 0 до 7) цифр, перед
которыми обязательно записан 0 - для компилятора это единственный признак
восьмеричного числа.
Пример: 0377
Десятичные литералы хорошо Вам знакомы и привычны, состоят из десятичных
цифр и НЕ могут начинаться с нуля.
Пример: 255
Шестнадцатеричные литералы состоят из шестнадцатеричных цифр (от 0 до F) и
всегда начинаются м префикса 0x или 0X (от латинского heX).
Для компилятора, пара символов 0x или 0X образует единый символ, признак
шестнадцатеричного числа.
Пример: 0xFF
Важно понять, что для компилятора не существует никакого способа
определить, в какой системе счисления записано число, кроме указанного
выше - по префиксу (или его отсутствию) перед числовым значением.
Количество допустимых цифр в литерале зависит от числа разрядов
конкретной машины и выбранного типа представления.
Так, если выбран "длинный" тип, то Вы должны сообщить об этом
компилятору с помощью суффикса l или L (от long).
Пример: 0x000000FFL
Кроме того, существует еще и суффикс u или U (unsigned) для
беззнаковых целых.
Вот выдержка из документации:
> Целые константы (K&R 2.4.1)
> ---------------------------
>
> Допускается использование десятичных констант в диапазоне
> 0...4294967295. (Отрицательные константы рассматриваются просто как
> беззнаковые, к которым применен унарный оператор "минус".) Восьмеричные
> и шестнадцатеричные константы также допустимы.
>
> Суффикс L (или l), присоединенный к любой константе, сделает ее
> представление типа long. Аналогично, суффикс U (или u), дает
> представление unsigned. Константа становится unsigned long, если ее
> значение превышает 65535, независимо от используемого основания.
> Примечание: можно использовать оба (L, и U) суффикса для одной и той же
> константы.
>
> В таблице 11.2 обобщены представления констант по всем трем основаниям.
>
> Таблица 11.2. Целые константы Турбо Си без L или U.
>
> __________________десятичные константы________________________
>
> 0-32767 int
> 32767-2147483647 long
> 2147483648-4294967295 unsigned long
> > 4294967295 будет переполнение без
> предупреждения; результат константы
> будет представлен младшими битами
> фактического значения
>
> __________________восьмеричные константы______________________
>
> 00-077777 int
> 0100000-0177777 unsigned int
> 01000000-017777777777 long
> 0100000000000-0377777777777 unsigned long
> > 0377777777777 будет переполнение (как описано
> выше)
>
> _________________шестнадцатеричные константы__________________
>
> 0x0000-0x7FFF int
> 0x8000-0xFFFF unsigned int
> 0x10000-0x7FFFFFFF long
> 0x80000000-0xFFFFFFFF unsigned long
> > 0xFFFFFFFF будет переполнение (как описано
> выше)
Как видите, все правила сводятся к тому, чтобы сделать разбор текста
программы однозначным, не допускающим различного толкования.
Литералы с плавающей точкой всегда десятичные и всегда представляют
данные с двойной точностью.
Если по какой-либо причине Вам нужен литерал с плавающей точкой с
одинарной точностью, Вы должны специально указать это с помощью
суффикса f или F (от float).
Более того, в Turbo C доступен тип long double (10 байт).
Вы можете указать этот тип для литерала с помощью суффикса l или L.
Таким образом, ситуация с литералами с плавающей точкой полностью
противоположна ситуации с целочисленными литералами: литералы с плавающей
точкой по умолчанию (default) имеют двойную точность, целочисленные
литералы по умолчанию имеют одинарную точность.
Легко понять почему целочисленные литералы имеют одинарную точность -
экономится память.
Причина же, по которой литералы с плавающей точкой имеют двойную точность
заключается в том, что все библиотечные функции С для работы с плавающей
точкой принимают аргументы и возвращают значение двойной точности.
Предполагалось (и эти ожидания оправдались), что язык С заменит Fortran в
качестве языка для научных расчетов, где двойная точность - обычное
требование.
Пример: 100.0
Символьные литералы представляются комбинацией из двух одиночных кавычек,
между которыми помещается произвольный символ таблицы ASCII, исключая саму
одиночную кавычку (apostrophe) и символ обратная косая черта (backslash),
которая имеет специальное значение (ESC-character).
Также допускается вместо символа ASCII записать его восьмеричный или
шестнадцатеричный код.
Восьмеричный код записывается в виде '\nnn', где nnn - одна, две или три
восьмеричные цифры.
Шестнадцатеричный код записывается в виде '\xnnn' или '\Xnnn', где nnn -
одна, две или три шестнадцатеричные цифры.
Как видите, по сравнению с записью обычных литералов, символ 0 всегда
опущен и, таким образом, не осталось возможности использовать в символьных
литералах десятичные значения - компилятор не сможет их опознать.
Наконец, по историческим причинам, существует еще несколько символьных
литералов, записываемых в виде '\L', где L - (от letter) - один из
следующих 12 символов: ", ', 0, ?, a, b, f, n, r, t, v, \.
'\"' - quote
'\'' - apostrophe
'\0' - null
'\?' - question sign
'\a' - bell
'\b' - backspace
'\f' - form feed
'\n' - new line
'\r' - carriage return
'\t' - tabulation
'\v' - vertical tabulation
'\\' - backslash
По самим этим названиям легко догадаться, что все они относятся к эпохе
телетайпов (электрических пишущих машинок), долгое время использовавшихся
в качестве недорогих устройств ввода/вывода в компьютерах (я еще застал их
- на ремонт чешского Consul'а уходила половина моего рабочего времени).
И вот из этих забытых времен перекочевали на электронные дисплеи '\r'-
возврат каретки, '\f'- смена страницы, '\b' - возврат на шаг, '\a' -
звонок, предупреждающий машинистку о конце строки, '\t' - клавиша
табуляции и '\n' - прокрутка валика на один интервал.
Имеется одно важное (и часто удобное), но непереносимое расширение
стандарта:
> Турбо Си поддерживает двухсимвольные константы, например, 'An', '\n\t'
> и '\007\007'. Эти константы имеют 16-битное представление типа int,
> причем первый символ находится в младшем байте, а второй в старшем.
> Запомните, что такие константы не переносимы в другие компиляторы Си.
Строковые литералы - это просто последовательность символов ASCII,
заключенная в двойные кавычки.
Пример: "The quick brown fox jumps over the lazy dog."
Если внутрь строкового литерала необходимо поместить символ " (quote), то
он предваряется ESC-символом '\' (backslash).
Напоследок, полезная таблица.
> Таблица 11.4. Типы данных, размеры и диапазоны в Турбо Си
> -----------------------------------------------------------------
> Тип Размер (в битах) Диапазон
> -----------------------------------------------------------------
>
> unsigned char 8 0 - 255
> char 8 -128 - 127
> enum 16 -32768 - 32767
> unsigned short 16 0 - 65535
> short 16 -32768 - 32767
> unsigned int 16 0 - 65535
> int 16 -32768 - 32767
> unsigned long 32 0 - 4294967295
> long 32 -2147483648 - 2147483647
> float 32 3.4E-38 - 3.4E+38
> double 64 1.7E-308 - 1.7E+308
> long double 80 3.4E-4932 - 1.1E+4932
> pointer 16 (указатели near,_cs,_ds,_es,_ss)
> pointer 32 (указатели far, huge)
Операторы
---------
Вот список всех операторов, взятый из Turbo Help
Precedence of Operators
Priority Operator Order of evaluation
1 () [] . -> left to right
2 ! ~ - ++ -- & * (type) sizeof right to left
3 * / % left to right
4 + - left to right
5 << >> left to right
6 < <= > >= left to right
7 == != left to right
8 & left to right
9 ^ left to right
10 | left to right
11 && left to right
12 || left to right
13 ?: right to left
14 = += -= etc. right to left
15 , left to right
В левой колонке указан приоритет оператора, в правой - связывание.
Обратите внимание, что некоторые операторы имеют правое связывание, то
есть, действие выполняется справа налево.
Самый высокий приоритет (1) имеют скобки, самый низкий (15) - оператор
запятая (comma).
Некоторые операторы (арифметические, логические, сдвига) Вам уже знакомы.
Конкретно о каждом операторе мы поговорим позднее, а пока несколько общих
замечаний.
Все операторы языка С делятся на унарные, имеющие только один операнд,
бинарные, имеющие два операнда и единственный тернарный оператор, имеющий
три операнда.
С точки зрения компилятора, оператор эквивалентен вызову функции с
соответствующим числом аргументов и в некоторых языках так и сделано - все
операции реализуются через вызов функций.
По счастью, в С сохранена обычная математическая нотация.
Некоторые операторы перегружены (overloading) и их значение зависит от
контекста.
Например, оператор '-' (minus) может быть унарным - используется для смены
знака, и может быть бинарным - вычисляется разность двух операндов.
Семантика унарных операторов '--' (decrement) и '++' (increment) различна
в зависимости от того, справа или слева от операнда они записаны.
Имейте ввиду, несмотря на запись в виде двух последовательных символов
'--' или '++', это один оператор, а не два минуса или два плюса, и
компилятор понимает их именно как один оператор decrement/increment.
-----[04]----------[Homework]---------------------------------------------
Вопросы не обязательно основаны на материалах выпуска и, как это обычно и
бывает в жизни, могут потребовать от Вас самостоятельного исследования.
1. Найдите учебник (грамматику) русского языка. Разберите структуру
русского предложения. Какие виды предложений бывают ? Из каких частей
речи они состоят ? Как (с помощью чего) осуществляется управление в
предложении ? Как строятся вопросительные предложения ?
2. Используя Ваше феноменальное знание русского языка, выберите несколько
десятков слов (не больше 100), которые могут претендовать на роль
ключевых (зарезервированных). Какие части речи попали в Ваш набор ?
3. Как Вы помните, Эллочка-Людоедочка обходилась всего 33 словами.
Можете ли Вы построить работоспособный диалект русского языка из
такого количества слов ? Каких ?
4. Опираясь на базовый набор резервированных слов языка С, подберите 50
русских слов для построения локализованной русской версии языка С.
-----[05]----------[Info]-------------------------------------------------
Вопросы и замечания принимаются по адресу: aleph@canada.com
Предыдущие выпуски доступны со страницы архива:
http://www.subscribe.ru/archive/comp.prog.c4dummies/
или (в упакованном виде):
http://members.xoom.com/c4dummies/archive/000.zip
. . .
http://members.xoom.com/c4dummies/archive/004.zip
-----[--]----------[The End]----------------------------------------------
© Gazlan 2009 * gazlan@yandex.ru
|