* C for Dummies * Aleph * 2000-09-11 * 011 * -----[00]----------[Quote of Day]----------------------------------------- If you think education is expensive, try ignorance Derek Bok -----[01]----------[Hot News]--------------------------------------------- Turbo Dump Version 5.0.13 Утилита фирмы Borland для просмотра и извлечения информации из двоичных файлов (.OBJ, .LIB, EXE). http://members.xoom.com/c4dummies/files/tdump.zip (73,060) -----[02]----------[Blah-Blah-Blah]--------------------------------------- Основополагающий принцип Дзюдо обычно переводят как "Победа - слабому", утверждая примат отточенной техники над грубой силой. Символичный бросок десятилетней японской девочки Natsumi Gomi, повергшей на татами российского президента, прекрасная тому иллюстрация. News: http://news.lycos.com/headlines/Entertainment/Oddly-Enough/article.asp?docid=RTODD-PUTIN-DC&date=20000905 http://dailynews.yahoo.com/h/nm/20000905/od/putin_dc_1.html Photo: http://dailynews.yahoo.com/h/p/nm/20000906/wl/imdf85941.html http://dailynews.yahoo.com/h/p/nm/20000906/wl/imdf85942.html а также здесь (новости + фото): "Putin Proves Pushover for Girl - on Judo Mat" (Reuters/Toshiyuki Aizawa/Tokyo) http://members.xoom.com/c4dummies/files/judo.zip (64,251) В программировании отточенная техника также намного важнее грубой силы, хотя есть ситуации, где применима только лобовая атака (Brute force). Но всякий раз, встретив новую для себя проблему, прежде всего пытайтесь нащупать ее "болевые точки", и тогда отточенный прием может разрешить все Ваши затруднения. -----[03]----------[Topic]------------------------------------------------ Pointers. Data Types. Declarations. -----[04]----------[Body]------------------------------------------------- Pointers -------- > Указатели типа FAR > ------------------ > > Указатель типа far (32-битный) содержит не только смещение в сегменте, > а также (как другую 16-битную величину) адрес сегмента, который затем > сдвигается влево и добавляется к смещению. Используя far-указатели, вы > можете иметь множественные программные сегменты, что позволяет > создавать программы величиной более 64К. Таким же образом far-указатели > могут адресовать данные, занимающие более 64К памяти. > > Когда вы используете far-указатели к данным, вы должны знать о > потенциальных проблемах в манипулировании указателями. Как объяснялось > в разделе "Вычисление адреса", вы можете иметь много различных пар > "сегмент:смещение", указывающих на один и тот же адрес. Например, все > far- указатели 0000:0120, 0010:0020 и 0012:0000 указывают на один и тот > же 20-битный адрес. Однако, если вы имеете 3 различных переменных > far-указателя - a, b и c, содержащие эти 3 величины соответственно, то > все следующие выражения будут работать неправильно: > > if (a==b) ... > if (b==c) ... > if (a==c) ... > > Указанная проблема появляется, когда вы хотите сравнить far- указатели, > используя операторы >, >=, <, <=. В этих случаях только смещение (как > беззнаковое) может использоваться в целях сравнения. Предположим, что > а, b и c имеют значения, описанные выше; тогда следующие выражения > будут верны: > > if (a>b) ... > if (b>c) ... > if (a>c) ... > > Операторы равенства (==) и неравенства (!=) используют 32-битную > величину как unsigned long (беззнаковую длину),а не как полный адрес > памяти. Операторы сравнения ( >, >=, < и <=) используют только > смещение. > > Для операторов == и != необходимы все 32 бита для того, чтобы можно > было произвести сравнение с NULL указателем (0000:0000).В противном > случае, если для проверки равенства вы используете только смещение, то > любой указатель со смещением 0000 будет равен NULL указателю, а это не > является тем, что вы хотите. > > Еще вам необходимо знать следующее. Если вы прибавляете величину к > far-указателю, то изменяется только смещение. Если результат сложения > превышает величину FFFF (это максимально возможная величина смещения), > то указатель делает циклический переход назад, к началу сегмента. > Например, результатом прибавления 1 к 5031:FFFF, будет 5031:0000 (а не > 6031:0000). Аналогично, если вы вычитаете 1 из 5031:0000, то получите > 5031:FFFF (а не 5030:000F). > > Если вы хотите сравнить указатели, то надежнее использовать или > near-указатели, которые всегда используют один и тот же адрес сегмента, > или huge-указатели, описание которых следует далее. > > > Указатели типа HUGE > ------------------- > > Указатели типа huge (также как и far) имеют 32-битную длину и содержат > как адрес сегмента, так и смещение. Однако, в отличие от far, они > нормализованы с целью решения проблем, рассмотренных в предыдущем > разделе. > > Что такое указатель типа huge ? Это 32-битный указатель, который имеет > наибольшую из возможных величину адреса сегмента. Так как сегмент > всегда начинается с адреса, кратного 16 (или 10h), то это означает, что > смещение может принимать значения от 0 до 15 (от 0h до Fh). > > Как нормализовать указатель ? Очень просто: переведите его в 20-битный > адрес, затем используйте правые 4 бита для смещения и левые 16 бит для > адреса сегмента. Например, дан указатель 2F84:0532; мы переведем его в > абсолютный адрес 2FD72, который затем нормализуется в 2FD7:0002. > Приведем несколько указателей и их нормализованные значения: > > 0000:0123 0012:0003 > 0040:0056 0045:0006 > 500D:9407 594D:0007 > 7418:D03F 811B:000F > > Теперь вы знаете, что указатели типа huge всегда хранятся > нормализованными. Почему это важно ? Потому, что для любого данного > адреса памяти имеется только один возможный указатель типа huge - пара > "сегмент:смещение". Это означает, что операторы >, >=, <, <= дадут > правильный ответ для любого указателя типа huge. > > Дополнительно к этому, все операторы >, >=, <, <= используют полную > 32-битную величину указателя типа huge. Нормализация гарантирует, что > их результат всегда будет корректным. > > И, наконец, благодаря нормализации, смещение в указателе типа huge > автоматически делает циклический переход, при достижении величины 16, > но, в отличие от far, сегмент также увеличивается. Например, если вы > увеличиваете 811B:000F, то результат будет 811C:0000; аналогично, если > вы уменьшаете 811C:0000, то получите 811B:000F. Эта особенность > указателей типа huge позволяет манипулировать структурами данных свыше > 64К. > > Однако при использовании указателей типа huge возрастают дополнительные > расходы. Арифметические операции над указателями типа huge выполняются > с вызовом специальных подпрограмм, и поэтому они выполняются гораздо > медленнее, чем над указателями типа near и far. Data Types ---------- В пятом выпуске мы уже немного говорили о типах данных (применительно к константам). Приведу сводную таблицу еще раз. > Типы данных, размеры и диапазоны в Турбо Си > ----------------------------------------------------------------- > Тип Размер (в битах) Диапазон > ----------------------------------------------------------------- > > 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) Вы можете видеть, что С предоставляет очень ограниченный набор базовых типов, напрямую имплементирующих машинные типы данных. Но их правильным выбором достигается машинная независимость. Основой является байт - наименьший непосредственно адресуемый участок памяти. Как правило, размер байта - 8 бит (сокращение от binary digit - двоичная единица, разряд). Размеры всех других типов всегда кратны байту. В С байт отображается на самый короткий целый тип - char - символьный. Для указания компилятору, как именно трактовать это целое - со знаком или без - используются два модификатора: signed - знаковый unsigned - беззнаковый. По умолчанию (опасный принцип, неизжитый со времен Fortran'а), все целые типы трактуются как signed и сам этот модификатор в таком случае может быть опущен. Иными словами, записи char и signed char для компилятора эквивалентны. Но, на самом деле, TC 2.0 предоставляет Вам несколько большую свободу: Вы можете зайти в Options | Compiler | Code generation | Default char type и выбрать между знаковым и беззнаковым типом по умолчанию. File Edit Run Compile Project Options Debug Break/watch +------------------------------------ Edit+------------------+-----------------+ | Line 1 Col 1 Insert Indent Ta| Compiler |NONAME.C | | | +---------------------------+ | | | | Model Small | | | | | Defines | | | | | Code generation | | | +--------------------------------------+| | | Calling convention C || | | Instruction set 8088/8086 || | | Floating point Emulation || | | Default char type Signed || Беззнаковый тип - это всегда положительное число, подчиняющееся обычным правилам арифметики по модулю, определяемом разрядностью регистра. Так, при разрядности байта в восемь бит, модуль равен 8. Разрядность (число байт) в типах short, int и long оставляется на усмотрение разработчиков компиляторов и, вообще говоря, может совпадать. Единственное (и естественное) требование: int не должен быть короче short, а long не должен быть короче int. На IBM/PC в 16-ти разрядных системах (DOS, Win16) совпадают short и int, в 32-х разрядной среде (Win32) совпадают int и long. На других компьютерах (других OS) или в компиляторах других фирм это может быть не так. Всегда будьте предельно осмотрительны, если работа Вашей программы зависит от размерности данных. В данной реализации (TC 2.0) символьный тип char всегда имеет размер 1 байт, int - 2, и long - 4. С любым из этих трех типов Вы можете использовать модификаторы signed и unsigned. Обычно, разрядность типа int совпадает с длиной машинного слова (в данном случае - 2 байта). Кроме того, существует еще один, очень специальный, целый тип - enum (от enumeration - перечисление), о котором мы поговорим позднее. Обычно, enum имеет такую же разрядность как и int и может приводиться к другому целому типу подходящего размера. Числа с плавающей точкой могут иметь один из трех типов: float, double и long double, в зависимости от требуемой точности. Практически все библиотечные функции для работы с плавающей точкой принимают и возвращают тип double, а тип long double не имеет почти никакой поддержки. Размер указателя (16 или 32 бит) будет зависеть от выбранной модели памяти и использованного модификатора: near, far, huge. Напомню еще раз, что нормализуются только указатели типа huge, и необходимо быть предельно внимательным с адресной арифметикой. По счастью, в Win32 (flat memory model) Вы будете избавлены от этой головной боли. Declarations ------------ C требует опережающего объявления всех используемых переменных - большой шаг к безопасному программированию по сравнению с Fortran или Basic. В отличие от C++, где объявление допускается почти в любом месте блока, в C объявления делаются только в начале блока. (О блоке Вам пока достаточно знать, что это все, что помещено между фигурными скобками '{' и '}' ). Каждый оператор в языке С должен оканчиваться символом ';' (semicolon). Примеры деклараций: /* ****************************************************************** ** @@ DECL - A program for testing Declarations ** ****************************************************************** */ void main() { unsigned char c1; signed char c2; char c3; unsigned short s1; signed short s2; short s3; unsigned int i1; signed int i2; int i3; unsigned long l1; signed long l2; long l3; float f; double d; long double ld; } /* ****************************************************************** ** @@ The End ** ****************************************************************** */ Выберем односегментную модель памяти (Tiny): File Edit Run Compile Project Options Debug Break/watch +------------------------------------ Edit+------------------+------------- | Line 1 Col 1 Insert Indent Ta| Compiler |DELC.C |/* **************************************| +---------------------------+ |@@ DECL - A program for testing Decl| | Model Tiny | |** **************************************| | Defines +---------+ | | | Code generation | Tiny | |void main() | | Optimization | Small | |{ | | Source | Medium | | unsigned char c1; +-| Errors | Compact | | signed char c2; | Names | Large | | char c3; +------------------| Huge | | +---------+ | unsigned short s1; Заявим, что имеем математический сопроцессор: Options | Compiler | Code generation | Floating point | 8087/80287 File Edit Run Compile Project Options Debug Break/watch +------------------------------------ Edit+------------------+-----------------+ | Line 1 Col 1 Insert Indent Ta| Compiler |DELC.C | |/* **************************************| +---------------------------+ | |@@ DECL - A program for testing Decl| | Model Small | | |** **************************************| | Defines | | | | | Code generation | | |void main() +--------------------------------------+| |{ | Calling convention C || | unsigned char c1; | Instruction set 8088/8086 || | signed char c2; | Floating point 8087/80287 || Закажем линкеру детальную карту памяти: Options | Linker | Map file | Detailed File Edit Run Compile Project Options Debug Break/watch +------------------------------------ Edit+------------------+-----------------+ | Line 1 Col 1 Insert Indent Ta| Compiler |DELC.C | |/* **************************************| Linker |******** ** | |@@ DECL - A program for testing Decl|+----------------------------------+| |** **************************************|| Map file Detailed || Сохраним установки: Options | Save options | Y File Edit Run Compile Project Options Debug Break/watch +------------------------------------ Edit+------------------+-----------------+ | Line 1 Col 1 Insert Indent Ta| Compiler |DELC.C | |/* **************************************| Linker |******** ** | |@@ DECL - A program for testing Decl| Environment | | |** **************************************| Directories |******** */ | | | Arguments | | |void main() | Save options | | |{ | +------------- Verify -------------+ | unsigned char c1; +-| Overwrite \TC\TCCONFIG.TC? (Y/N) | | signed char c2; +----------------------------------+ Скомпилируем и выполним эту программу (CTRL-F9). Как и следовало ожидать, ничего не случилось - ведь мы не предусмотрели в программе ничего, кроме деклараций. Изучим теперь выходные файлы компилятора. Их три, они имеют тоже самое имя, что и программа DECL и расширения (extensions) .OBJ, .MAP и .EXE DECL.MAP - это обычный текстовый файл, а .OBJ и .EXE - двоичные файлы, для просмотра не предназначенные. Тем не менее, иногда бывает любопытно сунуть нос и туда, где этого не ждут :-) Начнем с DECL.OBJ - можете открыть его в любом HEX-редакторе или вьювере. На самом деле, любителей поглядеть "А что у него внутри ..." так много, что Borland поставляет со своими компиляторами специальную утилиту TDUMP, для просмотра двоичных файлов и экстрагирования из них различной информации. Ей я и воспользуюсь. Turbo Dump Version 5.0.13.1 Copyright (c) 1988, 1997 Borland International Display of File DELC.OBJ 000000: 80 08 00 06 44 45 4C 43 2E 43 E9 88 1E 00 00 00 ....DELC.C...... 000010: 1A 54 43 38 36 20 42 6F 72 6C 61 6E 64 20 54 75 .TC86 Borland Tu 000020: 72 62 6F 20 43 20 32 2E 30 31 20 C9 88 0E 00 00 rbo C 2.01 ..... 000030: E9 FB 04 2A 29 06 44 45 4C 43 2E 43 A0 88 06 00 ...*).DELC.C.... 000040: 00 E5 01 00 00 8C 88 06 00 00 E5 01 03 00 89 88 ................ 000050: 05 00 00 E7 05 00 87 88 05 00 00 E7 05 00 87 88 ................ 000060: 03 00 00 E9 8C 88 05 00 00 EA 01 08 80 96 2F 00 ............../. 000070: 00 05 5F 54 45 58 54 04 43 4F 44 45 05 5F 44 41 .._TEXT.CODE._DA 000080: 54 41 04 44 41 54 41 04 5F 42 53 53 03 42 53 53 TA.DATA._BSS.BSS 000090: 06 44 47 52 4F 55 50 06 44 47 52 4F 55 50 F3 98 .DGROUP.DGROUP.. 0000A0: 07 00 28 05 00 02 03 01 2E 98 07 00 48 00 00 04 ..(.........H... 0000B0: 05 01 0F 98 07 00 48 00 00 06 07 01 0B 9A 06 00 ......H......... 0000C0: 08 FF 02 FF 03 55 90 0C 00 00 01 05 5F 6D 61 69 .....U......_mai 0000D0: 6E 00 00 00 5A 88 0B 00 00 E3 18 00 00 00 23 01 n...Z.........#. 0000E0: 00 00 4E 88 05 00 00 E1 18 18 62 A0 09 00 01 00 ..N.......b..... 0000F0: 00 55 8B EC 5D C3 6A 88 0F 00 00 E8 00 06 44 45 .U..].j.......DE 000100: 4C 43 2E 43 FB 04 2A 29 A0 94 0B 00 00 01 05 00 LC.C..*)........ 000110: 00 00 1A 00 03 00 3E 8A 02 00 00 74 00 00 00 00 ......>....t.... Гм. Любопытно. Фирма Borland описывает свой компилятор как TC86. Далее следует версия компилятора: "Borland Turbo C 2.01" и всякий мусор, среди которого мы можем разглядеть имена сегментов: _TEXT CODE _DATA DATA _BSS BSS DGROUP и DGROUP. Больше ничего интересного увидеть не удалось, перейдем к .EXE-файлу. Поскольку большая часть его состоит либо из нулей, либо из двоичного "мусора", я приведу только несколько фрагментов. Turbo Dump Version 5.0.13.1 Copyright (c) 1988, 1997 Borland International Display of File DELC.EXE 000000: 4D 5A 14 00 06 00 00 00 20 00 00 00 FF FF 00 00 MZ...... ....... 000010: 00 00 00 00 00 01 00 00 22 00 00 00 01 00 FB 20 ........"...... 000020: 72 6A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 rj.............. 000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ Это стандартный заголовок EXE-файла. Вас возможно удивит, но точно также он выглядит и в Win16 и Win32. 000840: 00 00 00 00 54 75 72 62 6F 2D 43 20 2D 20 43 6F ....Turbo-C - Co 000850: 70 79 72 69 67 68 74 20 28 63 29 20 31 39 38 38 pyright (c) 1988 000860: 20 42 6F 72 6C 61 6E 64 20 49 6E 74 6C 2E 00 44 Borland Intl..D 000870: 69 76 69 64 65 20 65 72 72 6F 72 0D 0A 41 62 6E ivide error..Abn 000880: 6F 72 6D 61 6C 20 70 72 6F 67 72 61 6D 20 74 65 ormal program te 000890: 72 6D 69 6E 61 74 69 6F 6E 0D 0A 00 00 00 00 00 rmination....... Ничего интересного: версия компилятора, сообщения об ошибках ... Этот код соответствует Runtime Library - исполняющей системе, код которой подключается к Вашему на этапе линкования. 000E10: 00 00 00 00 00 00 00 00 5F 5F 65 78 69 74 00 5F ........__exit._ 000E20: 5F 72 65 73 74 6F 72 65 7A 65 72 6F 00 5F 61 62 _restorezero._ab 000E30: 6F 72 74 00 44 47 52 4F 55 50 40 00 5F 6D 61 69 ort.DGROUP@._mai 000E40: 6E 00 5F 65 78 69 74 00 5F 5F 73 65 74 61 72 67 n._exit.__setarg 000E50: 76 00 5F 5F 73 65 74 65 6E 76 70 00 5F 61 74 65 v.__setenvp._ate 000E60: 78 69 74 00 5F 5F 5F 70 75 6C 6C 5F 66 72 65 65 xit.___pull_free 000E70: 5F 62 6C 6F 63 6B 00 5F 6D 61 6C 6C 6F 63 00 5F _block._malloc._ 000E80: 5F 5F 62 72 6B 00 5F 5F 5F 73 62 72 6B 00 5F 62 __brk.___sbrk._b 000E90: 72 6B 00 5F 73 62 72 6B 00 5F 5F 49 6E 74 30 56 rk._sbrk.__Int0V 000EA0: 65 63 74 6F 72 00 5F 5F 49 6E 74 34 56 65 63 74 ector.__Int4Vect 000EB0: 6F 72 00 5F 5F 49 6E 74 35 56 65 63 74 6F 72 00 or.__Int5Vector. 000EC0: 5F 5F 49 6E 74 36 56 65 63 74 6F 72 00 5F 5F 61 __Int6Vector.__a 000ED0: 72 67 63 00 5F 5F 61 72 67 76 00 5F 65 6E 76 69 rgc.__argv._envi 000EE0: 72 6F 6E 00 5F 5F 65 6E 76 4C 6E 67 00 5F 5F 65 ron.__envLng.__e 000EF0: 6E 76 73 65 67 00 5F 5F 65 6E 76 53 69 7A 65 00 nvseg.__envSize. 000F00: 5F 5F 70 73 70 00 5F 5F 6F 73 6D 61 6A 6F 72 00 __psp.__osmajor. 000F10: 5F 5F 76 65 72 73 69 6F 6E 00 5F 5F 6F 73 6D 69 __version.__osmi 000F20: 6E 6F 72 00 5F 65 72 72 6E 6F 00 5F 5F 38 30 38 nor._errno.__808 000F30: 37 00 5F 5F 53 74 61 72 74 54 69 6D 65 00 5F 5F 7.__StartTime.__ 000F40: 5F 68 65 61 70 62 61 73 65 00 5F 5F 5F 62 72 6B _heapbase.___brk 000F50: 6C 76 6C 00 5F 5F 5F 68 65 61 70 74 6F 70 00 5F lvl.___heaptop._ 000F60: 5F 68 65 61 70 62 61 73 65 00 5F 5F 62 72 6B 6C _heapbase.__brkl 000F70: 76 6C 00 5F 5F 68 65 61 70 74 6F 70 00 65 6D 77 vl.__heaptop.emw 000F80: 73 5F 6C 69 6D 69 74 53 50 00 65 6D 77 73 5F 69 s_limitSP.emws_i 000F90: 6E 69 74 69 61 6C 53 50 00 65 6D 77 73 5F 73 61 nitialSP.emws_sa 000FA0: 76 65 56 65 63 74 6F 72 00 65 6D 77 73 5F 6E 6D veVector.emws_nm 000FB0: 69 56 65 63 74 6F 72 00 65 6D 77 73 5F 73 74 61 iVector.emws_sta 000FC0: 74 75 73 00 65 6D 77 73 5F 63 6F 6E 74 72 6F 6C tus.emws_control 000FD0: 00 65 6D 77 73 5F 54 4F 53 00 65 6D 77 73 5F 61 .emws_TOS.emws_a 000FE0: 64 6A 75 73 74 00 65 6D 77 73 5F 66 69 78 53 65 djust.emws_fixSe 000FF0: 67 00 65 6D 77 73 5F 42 50 73 61 66 65 00 65 6D g.emws_BPsafe.em 001000: 77 73 5F 73 74 61 6D 70 00 65 6D 77 73 5F 76 65 ws_stamp.emws_ve 001010: 72 73 69 6F 6E 00 5F 5F 65 78 69 74 62 75 66 00 rsion.__exitbuf. 001020: 5F 5F 65 78 69 74 66 6F 70 65 6E 00 5F 5F 65 78 __exitfopen.__ex 001030: 69 74 6F 70 65 6E 00 5F 5F 68 65 61 70 6C 65 6E itopen.__heaplen 001040: 00 5F 5F 73 74 6B 6C 65 6E 00 5F 5F 61 74 65 78 .__stklen.__atex 001050: 69 74 63 6E 74 00 5F 5F 52 65 61 6C 43 76 74 56 itcnt.__RealCvtV 001060: 65 63 74 6F 72 00 5F 5F 53 63 61 6E 54 6F 64 56 ector.__ScanTodV 001070: 65 63 74 6F 72 00 5F 5F 61 74 65 78 69 74 74 62 ector.__atexittb 001080: 6C 00 5F 5F 5F 6C 61 73 74 00 5F 5F 5F 72 6F 76 l.___last.___rov 001090: 65 72 00 5F 5F 5F 66 69 72 73 74 00 43 30 54 00 er.___first.C0T. 0010A0: 43 30 54 00 44 45 4C 43 2E 43 00 44 45 4C 43 00 C0T.DELC.C.DELC. 0010B0: 44 45 4C 43 2E 43 00 45 58 49 54 00 48 45 41 50 DELC.C.EXIT.HEAP 0010C0: 4C 45 4E 00 53 45 54 41 52 47 56 00 53 45 54 45 LEN.SETARGV.SETE 0010D0: 4E 56 50 00 53 54 4B 4C 45 4E 00 41 54 45 58 49 NVP.STKLEN.ATEXI 0010E0: 54 00 4D 41 4C 4C 4F 43 00 42 52 4B 00 00 00 00 T.MALLOC.BRK.... Полный список всех библиотечных функций. В более поздних версиях, Borland стал снабжать свои компиляторы специальной утилитой TDSTRIP.EXE для удаления отладочной информации из файла (это, кстати, существенно уменьшает размер исполняемого модуля). Well. Для полного счастья нам не хватает только ассемблерного листинга. Получим его используя TCC с ключом -S > ifndef ??version > ?debug macro > endm > endif > ?debug S "delc.c" > _TEXT segment byte public 'CODE' > DGROUP group _DATA,_BSS > assume cs:_TEXT,ds:DGROUP,ss:DGROUP > _TEXT ends > _DATA segment word public 'DATA' > d@ label byte > d@w label word > _DATA ends > _BSS segment word public 'BSS' > b@ label byte > b@w label word > ?debug C E9FB042A290664656C632E63 > _BSS ends > _TEXT segment byte public 'CODE' > ; ?debug L 5 > _main proc near > @1: > ; ?debug L 26 > ret > _main endp > _TEXT ends > ?debug C E9 > _DATA segment word public 'DATA' > s@ label byte > _DATA ends > _TEXT segment byte public 'CODE' > _TEXT ends > public _main > end Гм. И что мы видим ? Назначения сегментов, метки для дебаггера и одну единственную исполняемую команду: 'ret'. А где же наши, столь тщательно описанные переменные ? Может быть в сегменте данных ? Нет, их нет и там ... и нигде ... Hell ! Что же стало со всеми нашими декларациями ? А ничего. Компилятор их принял к сведению. Поскольку никаких реальных действий с этими переменными не производилось, то и никакого кода сгенерировано не было - информация о типе и именах переменных была занесена во внутренние таблицы транслятора и исчезла с окончанием компиляции. Современные компиляторы выдают в таких случаях предупреждение об описанной, но неиспользованной переменной. Несколько слов о стиле деклараций. Язык С позволяет свободную форму записи (немалое новшество в эпоху Холлеритовских перфокарт), так что Вы можете записать всю программу в одну строку или, наоборот, писать каждый идентификатор с новой строки. Так вот, не делайте ни того, ни другого :-) void main() { <-- Здесь начинается внешний блок unsigned char c1; <-- Внутри блока все строки начинаются signed char c2; с одним и тем же отступом (indent) char c3; Величина этого отступа также предмет для споров. Borland по умолчанию использует 3, Microsoft - 4. Некоторые извращенцы - 2 или 5. С теми, кто делает 1 или не делает вообще, просто не о чем разговаривать. Я всегда буду использовать три пробела (и если Ваш редактор вставляет символы табуляции - немедленно измените установки так, чтобы табуляция заменялась на пробелы). В языке С допускается одновременная декларация нескольких переменных одного типа - списком. Например, так: int x, y, z; Никогда этого не делайте. Декларацию каждого идентификатора записывайте отдельной строкой. int x; int y; int z; Такая запись не только легче читается и модифицируется, но и позволит Вам избежать ошибок при объявлении указателей (мы еще поговорим об этом). -----[05]----------[Homework]--------------------------------------------- В рабочей директории компилятора TC 2.0 на Вашем диске можно обнаружить три файла с расширением .ASM (это комментированный исходный текст) и директорию LIB, содержащую большое число объектных файлов. Разберитесь (с помощью файла README) в их назначении и просто посмотрите "что у них внутри". Выясните, какой библиотечный файл является источником тех текстовых строк, которые Вы видите в дампе Вашей программы. -----[06]----------[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/010.zip Рассылка дублируется (только текстовый вариант) с сервера www.egroups.com Подписка: c4d-subscribe@egroups.com -----[--]----------[The End]----------------------------------------------

© Gazlan 2009 * gazlan@yandex.ru

Hit Counter