Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 55
Текст из файла (страница 55)
а неязык. Часто ех1егл "С" используется для компоновки процедур, написанных па гогггап или ассемблере, которые удовлетворяют соглашениям реализации С. Директива ех1егл "С" указывает (л олько) на соглашение о компоновке и не влияет на смысл вызова функции. В частности, функция, обьявленная ех1егл С", подчиняется проверке типов и правилам преобразования С++, а не менее слабым правилам С.
Например: ех!егп С' (п(Т(); /п/ и () ( ге!игпХ(1)( ) (г(г оитбко . 'функция не. охгодает аргумента Добавление ех1егл "С" к большому ко шчеству объявлений может причинять н еудоб- ства. Имеется механизм указания соглашения о компоновке для группы объявлений. Например; Нередко программы на С«» содержат фрагменты, написанные на других языках. Лналогично, довольно часто фрагменты кода С-»е используются как часть программ, написанных в основном на другом языке.
Могут встретиться определенные препятствия па пути подобного «сотрудничества> между фрагментами программ, написанных на различных языках, и даже между кодом, написанным на одном языке, но скомпилированном разными компиляторами. Например, различные языки и различные реализации компиляторов одного и того же языка могут отличаться использованием машинных реп!стров для хранения аргументов, расположением аргументов в стеке, размещением встроенных типов, таких как строки и целые, формой имен, передаваемых компилятором компоновщику, и полнотой проверки соответствия типов, требуемой от компоновщика. Чтобы помочь компоновщику, в обьявленпях ех1егл указывают соглашения ло козтоновке.
Например, в с.ледуюшем примере объявляется функция з/гсру () стандартной библиотеки С и С++ п указывается, что компоновка должна производиться в соответствии с соглашениями, прпнятымц в С: 9 2. Компоновка 251 ех1егл "С' ( сйаг' к1гсру (ей лг ", соле! айаг" „' !и! кггстпр (солк1 сйаг', сопк1сйаг~! !лгк1г!еп (сопк1 айаг'(, ехтегп "С" ( №!пс!ис!е кгг(пу.йъ Такая техн!ика обычно используется для создания заголовочного файла Сч + из заго- ловочного файла С. С другой стороны, можно воспользоваться директивами услов- ной компиляции Я 7.8,1) для создания заголовочного файла, общего для С н С.н-: №фйеу ср!икр!ик ехтегл 'С" ( №елд(т" гйаг' ки.ору (сйаг*, солк1сйаг'(, глг к 1гс гор ',сон к1 ей а г', сон к1 ей а г'(; !п1 к1г1ел (сопк1 айаг"(; №~Йе)' ср!икр!ик №еп41' Предопределенное пмя ср(икр(ик используется для того, чтобы исключить конструкциии С+ ~-, когда файл используется в качестве заголовочного в С.
В блоке спецификации компоновки могут быть любые объявления: !!любые ооъяелення, например: О определение (! объявление ! не определение) ех1егл "С"( слг д1, ехг !пгниг, ) В частности, область видимости н класс памяти переменных остаются прежними, поэтому д1 остается глобальной переменной — она определена, а не просто объяв ле- на. Для того чтобы объявить переменную без ее определения, вы должны указать ключевое слово ех1егп непосредственно в объявлении. Например: ех1егп "С'!п1дб; 19 объявление бек определения На первый взгляд зто выглядит странно. Однако, зто простое следствие сохранения смысла неизменным при добавлении "С" к внешнему объявлению и сохранения назначения файла при заключении его в блок спецификации компоновки.
Имя, которое должно быть скомпоновано в стиле С, можно объявить в пространстве имен. Пространство имен окажет воздействие на способ доступа к имени в программе на С т+, но не на то, как его видит компоновщик. Типичным примером является рг(п'у (( нз к1с(: Этой ко!ютрукцней, обычно называемой блоком еле!(ифиха!!ии колглонокки (Мпйаде Ыоск), можно воспользоваться для вклкочения целого заголовочного файла С таким образом, чтобы обеспечить использование указанного файла в С+ ъ.
Например: Глава 9.исходные файлы и программы 252 П(ПС1иа(ЕкСВ1йга> иоЫ/() ( вЫкргт у" ааеддравствуи, '); рг(п 1/ ('ха ар ааап") // правильно // оаи об кои н сап сл обал ь ной раа п1/О Даже при наличии явного квалификатора в1асрг)п11 вызовется все та же старая рг)л(Я из С Я 21.8). Обратите внимание, что это позволяет пам вклаочать библиотеки с компоновкой в стиле С в выбранные нами, а не глобальные пространства имен. К сожалению, подобная гибкость недоступна для заголовочных файлов, опредсляюаднх функции с компоновкой в стиле С+к в глобальном пространстве имен.
Причина в том, что компоновка сущностей С++ должна принимать во внимание пространства имен таким образом, чтобы сгенерированные объектные файлы отражали факт наличия илп отсутствия использования пространств имен. 9.2.5. Компоновка и указатели на функции ОРТкоипонуеапгя в стиле СЕ+ 1урейеХт1 аа*г7) (сопле во)й", сопв1 ооЫ'); ех1егп 'С" ( // СРТ колпо нуепи я в гтиле С 1уреде/Ы1 (*Сгт) (сопв1 иоЫ", сопе1 по(г(~; //стр коипонуется в гтиле С иоЫ увог1 (воЫ* р, веге 1п, иге 1вг, СРТстр1 О стр колтонуется в ггпиле Сч--ь иоЫ)вогг(иола)'р, иге 1п, вае 1иьгтстр); //гтр колтонуется в стиле С иоЫхвог1 (оо(а)к р, иге 1п, в(ге 1вг, СгТстр); //стр компонуется в ааааиле Сч-е ехгегп 'С" иоЫ увог1(иоЫ* р, в(ге 1 и, иге 1вг, г Татр), //сотраггО кокпонуетгя в стиле С-ь-ь ап1сотрпге (сопвгиоЫ', сопл1ио(га ).
//стар() колтонует л в сптле С ехгегп 'С' иц сстр (соаав1 иоЫ*, сопвг иоЫ'), При совместном использовании фрагментов кола на С и С ь ь в одной программе иногда возникает необходимость в передаче указателя на функцию, определенную в одном языке, функциям, определенным в другом. Если обе реализации двух языков разделяаот соглашения о кгампоновке и механизмы вызова функций, подобная персдача указателей на функции является тривиальной задачей Однако, в общем случае нельзя ожидать подобного сходствз, позтому нужно прелпринять специальные действия для обеспечения того, чтобы функция вызывалась ожидаемым образом.
При указании соглашения о компоновке в объявлении оно применяются ко всем типам функций, именам функций и именам переменных, помещенным в объявление (объявлеааия). Это делает возможными все варианты странных на вид, но иногда имеющих большое значение комбинаций компоновки. Например: 253 9.3 использование заголовочных файлов ооиЦ(сдаг* о, га! кг( ( О ошибка О праеш!ьно уког! (о, кг, 1, 8сол!Расе! укос! (о, кх, 1, Йссо!р(. Д праепльло Г7ошибка ьког! (о, кг, 1, Бсотраге(, lког l (о, кх, 1, Йсстр! Реализации, в которых С и Се+ используют одинаковые соглашения о вызовах, мо- гут принять случаи, помеченные как ошибочные, в качестве расширений языка. 9.3.
Использование заголовочных файлов Я б.1, у 8.2). 9.3.1. Единственный заголовочный файл Простейшим решением проблемы разбиения программы на несколько файлов является помещение определений в подходящее число.с файлов, а объявлеш!й типов, необходимых пм для взаимодействия, в единственный .й файл, который будет вкпочеп в каждый .с файл, Для программы калькулятора мы можем воспользоваться пятью .с файлами — 1ехег.с, рагкег.с, 1аб1е.с, егго!..с и така.с — для хранения функции н определений д пшых, и заголовочным файлом г1с.й для хранения объявлений каждо го имени, используемого более чем в одном с файле. Заголовочньш файл с(с.й мог бы выглядеть следующим образом: Тг' бс.1н патекрасе Еггог( к!гис! Хего Й1о1с1е ( ); к!гис! Буп!ат еггог ( соле!еда! р, Буп!ах еггог (сопк! слог*у( (р = у, ) и1пс1и!1е <к !г(пу> патекрасе Еехег( епшл Тодеп оп!ие( МАМЕ, 1ЧЮМВЕЙ, РЕ11Б=' -', МВ'11Б='-', РИНТ=', АББТГк!Ч='— " ', ); ЕМТе, МЫ; — '*', ВЛ =-У', Еркз (', йР='(' ехгегп Тодеп иа(ие сигг !од; ехlегп г1оиЫе питбег оа1ие; ех!егп кйу Мг1пук!г1пд оаlие; Тоуеп оаlие уе! !одел ((; Для иллюстрации использования заголовочных файлов я представлю несколько различных способов выражен!!л физической структуры программы калькулятора Глава 9.Исходные файлы и программы 254 патеярасе Рагяег( с1оиЫе рг!т (Ьоо(уе1~; с(пи 6!е 1етп (Ьоо! уе1) с(оиЬ!е ехрг (6ооl уе1); О обработка нерванньм вира ясеня а О ултож ение и деление 0 сложение и вини(пание ияй!у Ьехеп.уег 1одеп; иягпуйехег:сиге 1од; и!пс!ис(е <тар> ех1егп я!с!:тир<я!с!септик, с!оиЫе> 1аЫе, патеяра се Вг!оег ( ех1ет! пи по оУ еггогя; ехlегп я1с!..!яггеат' три!, иои1 яЫр ().
) Ключевое слово ех1егп используется в каждом объявлении переменных для гарантии того, что нс произойдет множественных определений после того, как мы включим ас.Ь в различные.с файлы. Определения находятся в соответствующих.с файлах. За вычетом реального кода 1ехег.с будет выглядеть следующим образом: 1'1 !ехсш' и!пс!абе 'с!с.Ь" ПЬ!с!ис!е <!оясгеат> ПЬ!с!и!(е <сс1уре йехегсТодеп оа!иейехег..сиге !оЬ; с1оиЫе Ьехег,питЬег иа!ие; яЫ>я1ггпуйехег;я1г!пд иа!ие, Ьехег;Тодеп ип!ие секес.уе1 1оЬеп () ( 1*., '1) Использование заголовочных файлов подобным образом обеспечивает гаранппо того, что каждое объявление в заголовочном файле будет помещено во включаюпшй файл.
Например, при компиляции 1ехекс, компилятору будет выдано: па теяра се Ьехег ( 1! из с!с.Ь П.. ТоЬеп иаlие уе! lодеп (); Ьехег:Тодеп иа!иесехегуе1 1одеп () ( /' ...*1) Это гарантирует, что компилятор оонаружнт любые несоответствия типов, указываемых для имени. Например, если бы де! 1ойеп () был объявлен с типом возвращаемого значения Тойеп па1ие, а определен с !п1, компиляция 1ехекс завершилась бы неудачей с сообщением об ошибке несоответствия типов. Если определенно отсутствует, компоновщик обнаружит вту ошибку. Если отсутствует объявление, в одном из .сфайлов ошибку обнаружит компилятор. Файл рагяег,с будет выглядеть следующим образом; 255 9.3.
Использование заголовочных файлов //рагкег.с: и!лс!ис!е "с!с.Ь с!опЫе Риске г, реет ]Ьоо! де1) ] /' ... '/ ) с1оиЫе Рагкег<!егт ]Ьоо! дей ( /* ... "! ) с!оиЫе Рагкег екрг]Ьоо! де!) ]/* ... */) Файл 1аЫе.с будет выглядеть следующим образом: 0 1оЫе.с: и!лс!ис1е 'с!е Ь ксс!стар<к!с!.хсг!ссд, с!оиЫе> 1аЫе, Таблица символов является просто переменной стандартного библиотечного типа тар. Это определяет 1аЫе в качестве глобальной переменной. В программе реального размера подобные глобальные объявления рано плп поздно вызовут проблемы. Я оставил зту <неуклюжесть» с единственной целью — прелупредить о ней. Наконец, та! п.с будет выглядеть следующим образом: // таш.с; ислс1ис!е'с!еЬ' ислс1ис!е <кк1геат> и!ссс!ис!е <!ок1геат> ии!>г!пег ло о/ еггош = 0; ксс! ск1геит Рг!иег шри1= 0; ио!с! !Зг!иелкЬ!р ]) ] /* ...