Турбо С: руководство пользователя. Часть 2

Турбо С: руководство пользователя. Часть 2 - Стр. 43

Печать PDF
Индекс материала
Турбо С: руководство пользователя. Часть 2
Стр. 2
Стр. 3
Стр. 4
Стр. 5
Стр. 6
Стр. 7
Стр. 8
Стр. 9
Стр. 10
Стр. 11
Стр. 12
Стр. 13
Стр. 14
Стр. 15
Стр. 16
Стр. 17
Стр. 18
Стр. 19
Стр. 20
Стр. 21
Стр. 22
Стр. 23
Стр. 24
Стр. 25
Стр. 26
Стр. 27
Стр. 28
Стр. 29
Стр. 30
Стр. 31
Стр. 32
Стр. 33
Стр. 34
Стр. 35
Стр. 36
Стр. 37
Стр. 38
Стр. 39
Стр. 40
Стр. 41
Стр. 42
Стр. 43
Стр. 44
Стр. 45
Стр. 46
Стр. 47
Стр. 48
Стр. 49
Стр. 50
Стр. 51
Стр. 52
Стр. 53
Стр. 54
Стр. 55
Стр. 56
Все страницы
               Объявление указателей как NEAR, FAR или HUGE                     
     -----------------------------------------------------------------          
                                                                                
          Вы уже видели,  зачем вам может понадобиться объявлять функ-          
     ции для различных моделей памяти,  применяемых в программе. А за-          
     чем может понадобиться делать то же самое с указателями?  По при-          
     чинам,  что  уже  описанны  выше:  во  избежание  необоснованного          
     расширения (объявив near, когда по умолчанию должно быть far) или          
     чтобы  обратиться к чему-либо,  находящемуся вне допустимого сег-          
     мента (объявив far или  huge,  когда  по  умолчанию  должно  быть          
     near).                                                                     
                                                                                
          Встречаются, конечно,  потенциальные  ловушки  в  присвоении          
     функциям и указателям типов,  отличных от принятых по  умолчанию.          
     Например,  предположим, вы имеете следующую малую модель програм-          
     мы:                                                                        
                                                                                
     void myputs(s)                                                             
     char *s;                                                                   
     {                                                                          
          int i;                                                                
          for (i = 0; s[i] != 0; putc(s[i]);                                    
                                                                                
     }                                                                          
                                                                                
     main()                                                                     
     {                                                                          
          char near *mystr;                                                     
                                                                                
          mystr = "Hello, world\n";                                             
          myputs(mystr);                                                        
     {                                                                          
                                                                                
          Эта программа  работает  прекрасно,   а объявление mystr как          
     near излишне,  т.к.  все указатели,  как программы, так и данных,          
     будут near.                                                                
                                                                                
          Но что  будет,  если вы перекомпилируете эту программу,  ис-          
     пользуя компактную (или большую,  или  огромную)  модель  памяти?          
     Указатель mystr в main будет все еще near (это по-прежнему 16-би-          
     товый указатель).  Однако указатель s в myputs теперь  far,  т.к.          
     это устанавливается по умолчанию.  Это означает, что myputs будет          
     выбирать 2 слова из стека,  создавая far-указатель,  и полученный          
     адрес будет, несомненно, другим, чем у mystr.                              
                                                                                

                         - 353,354 -
                                                                                
          Как вам решить эту проблему? Решается она следующим образом:          
     myputs объявляется в стиле современного Си, т.е.:                          
                                                                                
     void myputs(char *s);                                                      
     {                                                                          
          /*body of myputs*/                                                    
     }                                                                          
                                                                                
          Теперь, когда  Турбо Си компилирует вашу программу,  ему из-          
     вестно, что  myputs предполагает указатель на char,  и,  т.к.  вы          
     компилируете в рамках большой модели,  указатель должен быть far.          
     Поэтому Турбо Си будет помещать регистр сегмента данных  (DS)   в          
     стек совместно  с 16-битной величиной mystr,  формируя far-указа-          
     тель.                                                                      
                                                                                
          Как быть в обратном случае:  параметры для myputs  объявлены          
     как far и компилируются для малой модели памяти?  Без использова-          
     ния прототипа функции вы столкнетесь с проблемами,  т.к. main бу-          
     дет помещать в стек как смещение, так и адрес сегмента, но myputs          
     предполагает только смещение.  При определении прототипа  функции          
     main будет помещать в стек только смещение.                                
                                                                                
                                                                                
                                                                                
          Вывод: если  вы  собираетесь  использовать  явное объявление          
     указателей как near или far,  то надежнее всего использовать про-          
     тотипы функций для любых функций,  где вы планируете их использо-          
     вать.                                                                      
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                

                         - 355,356 -
                                                                                
                                                                                

          Способ указания на данный сегмент: Offset адрес (смещение)            
     -----------------------------------------------------------------          
                                                                                
          Каким образом вы можете указатель типа far разместить в дан-          
     ной ячейке памяти (специальном сегменте - offset адресе)?  Вы мо-          
     жете воспользоваться встроенной библиотечной подпрограммой MK_FP,          
     которая  выбирает сегмент и смещение и возвращает far- указатель.          
     Например:                                                                  
                                                                                
          MK_FP(segment_value, offset_value)                                    
                                                                                
          Данный far-указатель (fp) может быть и сегментом FP_SEG(fp),          
     и смещением FP_OFF(fp). Для более детального ознакомления с этими          
     тремя библиотечными подпрограммами Турбо Си следует  обратиться к          
     "Справочному Руководству по Турбо Си".                                     
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
           Построение простых операторов объявления                             
     -----------------------------------------------------------------          
                                                                                
          Операторы объявления в Си вы используете для объявления  ти-          
     пов функций,  переменных,  указателей и данных.  Си позволяет вам          
     строить комплексные операторы объявления.  В этом разделе  даются          
     некоторые примеры операторов объявления, которые могут помочь вам          
     в их построении (и прочтении); будет также показано, как избежать          
     некоторые ловушки.                                                         
                                                                                
          Традиционно программирование  на  Си  дает возможность сразу          
     строить полный оператор объявления,  вставляя  при  необходимости          
     определения.  К сожалению, это делает программы сложными для чте-          
     ния (и написания).                                                         
                                                                                
          Например, рассматриваемые в таблице 12.3 операторы  объявле-          
     ния предполагают, что вы компилируете в рамках малой модели памя-          
     ти (малая программа, малые данные).                                        
                                                                                
     ННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН          
          int f1();                      Функция, возвращающая целое.           
                                                                                

                         - 357,358 -
                                                                                
          int *p1;                       Указатель на целое.                    
                                                                                
          int *f2();                     Функция, возвращающая указа-           
                                         тель на целое.                         
                                                                                
          int far *p2;                   Far- указатель на целое.               
                                                                                
          int far *f3();                 Near- функция, возвращающая            
                                         far- указатель на целое.               
                                                                                
          int *  far  f4();              Far-функция,  возвращающая             
                                         near-указатель на целое.               
                                                                                
          int (*fp1) (int);              Указатель на функцию, возвра-          
                                         щающую целое   и  принимающую          
                                         целое.                                 
                                                                                
          int (*fp2) (int *ip);          Указатель на функцию, возвра-          
                                         щающую  целое  и  принимающую          
                                         указатель на целое.                    
                                                                                
          int (far *fp3)(int far *ip)    Far-указатель на функцию,воз-          
                                                                                
                                         вращающую целое и принимающую          
                                         far-указатель на целое.                
                                                                                
                                                                                
          int (far *list[5]) (int far *ip);                                     
                                         Массив из 5 far-указателей на          
                                         функции, возвращающие целое и          
                                         принимающие far- указатели на          
                                         целое.                                 
                                                                                
          int (far *gopher(int (far *fp[5])(int far *ip)))(int far *ip);        
                                                                                
                                         Near-функция, принимающая мас-         
                                         сив из 5 far-указателей на фу-         
                                         нкции,  возвращающие  целое  и         
                                         принимающие  far- указатели на         
                                         целое, и  возвращающая один из         
                                         этих указателей                        
     НННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН         
                                                                                
               Таблица 12.3. Объявление указателей без typedef                  
                                                                                

                         - 359,360 -
                                                                                
          Здесь представлены все допустимые операторы объявления в по-          
     рядке возрастания трудности их восприятия.  Однако,  благоразумно          
     используя  typedef,  вы  можете  усилить четкость восприятия этих          
     операторов.                                                                
                                                                                
          Ниже представлены те же операторы, записанные с  использова-          
     нием typedef.