GCC - The Complete Reference (537669), страница 21
Текст из файла (страница 21)
Далее предлагается пример использования "прозрачного" объединения для вызова одной и той же функции с тремя различными типами аргументов: Глава 4. Компиляция программ на языке С 93 Я)ревут Оласалла 1лк аа1п(1пк агяс,сЬаг *агат() ) ( 1пг 1ча1ие = 2562( Г1оас Егере 090.44 г Еоигьугез ЙЬг ЕЬ.1 а1ча1сег вьоиьось(41чз1ие]г епоиьогь(асчз1се)( еьоиЬогь(ЕЬ)г гесигп(0)г ) чей зЬоиЬоьщ Йоигьугее ЕЫ г ( рг1акс("тье 1пк ча1иег аатп",*ЕЬ. 1) г рг1ягя("чье 11оаг чазсе: тгстл",*ЕЬ.Е) г ФуНКцИя еЬОиЬагь() З ПрИВЕдЕННОМ ПрИМЕрЕ ОбьяВЛЕНа КаК трЕбуЮщая Объединения соогь1Сее Е КачЕСтеЕ аргуМЕнта. Однако, благодаря тому, что зто объединение объявлено с атрибутом сгапзрагесс сл1оп, любые типы, объявленные з обьединении, также могут передаваться з аргументе функции.
Этот пример содержит вызовы указанной функции, передающие ей адрес числа с плавающей точкой, адрес целого числа и адрес собственно объединения. Применение такого атрибута при объявлении типа приводит к тому, что использование данных етого типа не ожидается. Позтому какие-либо предупреждения из-за их неиспользования не будут выдаваться компилятором. шюева Составные операторы, возвращающие значение ~Соароцпд йа1еаепЬ йе1цгапд а Ча!ие) ( 1пе а = 5) 1пе Ь) Ь= а+ 5( ) В б)ч('() С составной оператор, окруженный скобками, вырабатывает возвращаемое значение; как в следующем примере, где возвращаемое значение равно 8: гагс = (( 1пе а = 5) 1пс Ь) Ь=а+Зг ))) Составные операторы (сон)роип() з(а(ел)еп() — это блок операторов, заключенный в фигурные скобки. Они имеют собственную область действия и в них могут обьявляться собственные локальные переменные.
Пример: 94 Часть (!. Использование Сборного Компилятора Возвращаемое значение имеет тот же тип и значение результата, что и выражение в последнем операторе блока. Эта конструкция может быть весьма удобна при написании макросов. Иногда могут возникать проблемы, например, когда макрос имеет в качестве аргумента выражение, определяемое более одного раза. В следующем примере макрос возвращает значение, равное либо большее заданному, при необходимости инкрементируя его значение; Ваес1пе ечеп(х) (2*(х г' 2) = х ? х < х + 1) Это будет работать, несмотря иа возможность побочного эффекта вычисления значения х. Например, следующее выражение может давать неопределенный результат: апе пехге1геп = ечеп(че1пе++) Следующее макроопределение выполняет ту же задачу, но делает это, определяя значение выражения х один раз и сохраняя его во временной переменной: «г)агапе ечеп(х) (( зпе у = х; (2*(у г 2) == у у : у + З)г Х )) Следует заметить, что описываемое расширение не будет корректно работать в С++.
Если вы будете использовать этот прием в заголовочных файлах, включаемых в программы на языке С++, то это может вызвать проблемы. Трудности происходят оттого, что деструкторы временных переменных, используемых внутри макроса, запускаются раньше, чем это действует в (и!!пе-функциях, расширяемых подстановкой кода. Условный пропуск операнда (СопсЫопа! Орегапд Опньяоп) В условных выражениях ложное либо истинное условие определяется как нулевой либо ненулевой результат проверяемого выражения. Может случится так, что проверяемое выражение определяется и как результат всего условного выражения.
Например, в следующем операторе, х будет присвоено значение у, усли у не равно нулю: и=угу: зг Выражение у будет вычисляться второй раз, если при первом вычислении оио оказалось отличающимся от нуля. Есть способ пропустить повторное вычисление выражения, как это показано в следующем примере: х=ут: з Это может очень пригодиться, если вычисление выражения у имеет побочный эффект и ие должно определяться более одного раза в пределах одного оператора. Глава е. Компиляция программ иа языке С 95 Неполные перечисляемые типы (Гпца! псов р!е1е Турец) Ярлык епша может быть объявлен без указания списка зачений, так же как и имя структуры может объявляться без назначения содержащихся в ней полей.
Неполные перечисления могут использоваться в прототипах функций и для объявления указателей. В примере показано объявление неполного перечисления, сопровождаюшееся затем его действительным объявлением; епиа со1ог 11всг епяа со1ог 11вс ( вьдск, иихтл, выли ); Построение аргументов функций (Гипсбоп Агяцаеп1 Сопйгисбоп) Три приводимые встроенные функции могут использоваться для прямой передачи аргументов текущей функции в другую функцию и последующего возвращения результата в первоначальную вызывающую структуру. Для функции, передающей аргументы, вовсе не обязательно что-либо о них знать.
Следующая функция передает и записывает описываюшую аргументы информацикк чоИ * Ьп11еьп арр1у агдв(чо1д)г Когда информация об аргументах записана, может быть использована следуюшая фуикция, чтобы построить стэк информации, необходимой для вызова, и, собственио, осушествить вызов нужной функции: чоЫ * Ьп11сьп арр1у(чо1(( (егппс) (), чо1(( *агдопепев, 1пс в1ве) Первый аргумент — адрес функции, передаваемый как адрес функции, не имеющей аргументов и не возвращающей значение.
Второй — результат процеса записи, выполненного функцией Ьп11ейп арр1у агдв (). Аргумент вйге — количество байт для копирования из текущего кадра стэка (а(асй (гап)е) в новый кадр стэка, он даскен иметь достаточный размер для передачи всех аргументов вместе с возврашаеиым адресом. После того как вызвана функция Ьи11е1п арр1у() возвращаемое ею значеияе будет позиционировано в стэке.
Следую шая функция выравнивает кадр стэка и иоврщдает управление первоначальной вызывающей структуре: Ьи11с1п гесигп (чо1о *гевп1с] Приведенная далее в примере программа вызывает функцию равспгопдЬ ( ), использующую описанные встроенные функции для вызова ачегаде ( ) и возврашеиия ее результата: /* егдв.с ° Р ()(по1иде <всоьо.
Ь> 9б Часть!!. Использование Сборного Компилятора 1пе раеасЬгопдЬ(); !.пе ачегеде О; 1пг ша1п(1пг. агдс,сЬаг »агдтг()) ( 1пе геап1с1 гееи1е = ревасигоидЬ( 1,7,10)т рг1пег (»геепХГ»титтп",гевп1Е) ~ геепгп(О); ) 1пс рааегигоидЬ(1пе а,1пе Ь,1пс с) ( чс1с»гесогттт чо1с »р1ауЬасхт чоаа (» гп)() (чо1(( (*) О )ачегадет гееог(( = Ьп11Е1п арр1у агда()> р1ауЬаех Ьп11С1п арр1у(яп,гесогс,128)т Ьп11г1п геспгп(р1ауьае)с)т ) 1пе ачегеде(1пг а,1пс Ь,1пг с) ( геспгп((е + Ь + е) / 3)т ) Обратите внимание, что функции раввЕЬгопдЬ() известны аргументы и возвращаемое значение только потому, что это ее собственные аргументы и результат. Эта функция может быть преобразована в оболочкудля обобщенного вызова функций, если применить троеточие для создания открытого списка аргументов и объявить указатель на элемент данных (чо(б рош(ег) для передачи возвращаемого значения.
ТогдараввеЬгопдЬ() можно применятьдля передачи произвольного набора аргументов в функцию, известную по ее адресу. Возвращаемое значение также будет произвольного типа. Для написания такой обобщенной оболочки (йепегайгеб тчгаррег), необходимо учитывать, что величина в1*е, сообщаемая функции Ьп11е1п арр1у(), должна быть лостаточной для того, чтобы вместить все аргументы. Расширение вызовов функций подстановкой кода (Гысбоп! и! Ыпя) Фуяция может быть объявлена как расширяемая подстановкой (1п1(пе), и ее код будет подстанавливаться в месте ее вызова подобно тому как подстанавливаются макросы. Для объявления такой функции используется ключевое слово 1п11пе: 1п11пе 1пс Ьа1че(6епЬ1е х) ( геспгп (х I 2.0); ) Далее приводится список правил, действующих на расширяемые подстановкой функции: 4А Глава 4. Компиляция программ на языке С 97 ° Ни одна функция не будет в действительности подстанавливаться своим кодом определения„если вы не примените при компиляции опцию -о, назначающую тот или иной уровень оптимизации.
Это правило действует для упрощения применения программы-отладчика (деЬцяйег). Несмотря на это можно принудительно включать обязательное применение подстановки атрибутом а1маув Ьп1йпе. ° В результате объявления функции как расширяемой подстановкой кода, объем программы может увеличиться или уменьшиться в зависимости от размера кода функции, сложности установки кадра стека для вызова функции (саП 1гагпе), и количества вызовов функции в коде программы.