Чому C забезпечує мовні "прив'язки", коли C ++ не вистачає?


60

Нещодавно мені було цікаво, коли використовувати C над C ++, і навпаки? На щастя, хтось мене вже обіграв, і хоча це зайняло певний час, я зміг перетравити всі відповіді та коментарі до цього питання.

Однак один пункт у цій публікації постійно і знову звертається без будь-якого прикладу, перевірки чи пояснення:

"C код корисний, коли ви хочете мати кілька мовних прив’язок для вашої бібліотеки"

Це парафраза. Слід зазначити, що декілька людей зазначають, що в C ++ (через деяке externфункціонування) можливі кілька прив'язок мови , але, тим не менш, якщо ви прочитаєте цю публікацію в повному обсязі, то цілком очевидно, що C ідеально підходить для мобільності / прив'язки мови. Моє запитання: чому?

Чи може хтось надати конкретні причини, чому запис бібліотек на C дозволяє спростити прив’язку та / або переносимість іншими мовами?


6
Переважно з історичних та соціальних причин. Більшість мовних реалізацій та систем виконання створені вище C. Наприклад, час роботи Ocaml, SBCL, Haskell кодується в C (і не зароблять багато, перекодуючись у C ++)
Basile Starynkevitch

8
На практиці склеювати справжні бібліотеки C ++ (подумайте про Qt) у ці часи роботи болісно.
Василь Старинкевич

3
@Basile: Qt не є справжньою бібліотекою C ++. Крім того, навіть для більш болісних бібліотек це лише болісно, ​​оскільки вони виражають фактично корисну семантику.
DeadMG

2
Напівфабрикат: programmers.stackexchange.com/a/185159/20756
Blrfl

2
Прочитайте Основні COM від Don Box. Це пояснює процес створення ABI в C ++. COM - це спосіб Microsoft створити ABI. тобто бібліотеки COM C ++ можуть використовуватися з C або VB або інших мов.
user93353

Відповіді:


69

У C є набагато простіший інтерфейс, і його правила перетворення інтерфейсу вихідного коду у бінарний інтерфейс досить прості, що генерація зовнішніх інтерфейсів для прив’язки здійснюється чітко встановленим чином. C ++, з іншого боку, має неймовірно складний інтерфейс, і правила прив'язки ABI взагалі не стандартизовані ні формально, ні на практиці. Це означає, що майже будь-який компілятор для будь-якої мови для будь-якої платформи може прив’язатись до зовнішнього інтерфейсу С і точно знати, чого очікувати, але для інтерфейсу C ++ це по суті неможливо, оскільки правила змінюються залежно від того, який компілятор, яка версія та яка. платформу, на якій був побудований код C ++.

У C немає і стандартних правил реалізації бінарних мов, але це на порядок простіше і на практиці компілятори використовують ті самі правила. Ще одна причина, що робить C ++ важким для налагодження, - це вищезазначена складна граматика, оскільки налагоджувачі часто не можуть мати справу з багатьма мовними особливостями (розміщувати точки прориву в шаблонах, команди розбору покажчиків розбору у вікнах відображення даних тощо).

Відсутність стандартного ABI (бінарного інтерфейсу програми) має ще один наслідок - це робить доставку інтерфейсів C ++ іншим командам / клієнтам недоцільним, оскільки код користувача не працюватиме, якщо він не компільований з тими ж інструментами та параметрами збирання. Ми вже бачили ще одне джерело цієї проблеми - нестабільність бінарних інтерфейсів через відсутність інкапсуляції часу компіляції.

- Несправний С ++


4
Ви повинні зауважити, що, хоча можна визначити C-подібний API, реалізований у C ++ (для extern "C"цього все ж є додаткова робота, яку слід збалансувати за допомогою функцій, що надаються C ++)
jhominal

5
ABI C ++ не має значення в контексті питання, куди можна легко експортувати бібліотеки C ++ extern "C".
DeadMG

12
@jhominal: Це набагато краще, ніж писати його на C, де ви повинні визначити інтерфейс C, а потім вам також потрібно реалізувати його в C, тоді як у C ++ ви можете визначити інтерфейс C, і тоді вам не потрібно реалізовувати це в C. Незалежно від того, на якій мові ви реалізуєте, вам все-таки потрібно визначити інтерфейс C - це, звичайно, вірно в C ++, як це є в C або будь-якій іншій мові, яка може піддавати C прив'язки.
DeadMG

9
Чи можна було б додати відмову до посилання на цей FQA-диск?
Мартін Ба

2
@DocBrown: Впевнений, мені здається, що питання стосується мовних зв'язків C проти мов C ++.
Мейсон Уілер

32

Якщо ви намагаєтесь спілкуватися з носієм іншої мови, підгін простіше, ніж шекспірівська англійська.

Концепції C - виклики функцій, покажчики, рядки, що закінчуються NULL - дуже прості, тому інші мови можуть легко реалізувати їх досить добре, щоб викликати функції C. З історичних причин багато інших мов реалізовані в C, що робить виклик функцій C ще простішим.

C ++ додає зовсім небагато матеріалів - класів із спадщиною та vtables та модифікаторами доступу; винятки, із розмотуванням стека та зміною потоку управління; шаблони. Все це ускладнює використання інших мов на C ++ прив'язках: у кращому випадку для впровадження є більше "клею" або коду сумісності, а в гіршому випадку поняття не перекладаються безпосередньо (через відмінності в моделях класів, обробку винятків, тощо). Зокрема, для шаблонів просто їх використання (інстанціювання) зазвичай вимагає кроку компіляції з компілятором C ++, що значно ускладнює їх використання в інших середовищах.

Зважаючи на все це, можна переоцінити труднощі забезпечення прив’язки бібліотеки C ++ до іншої мови:

  • Прив'язки C ++ можуть бути настільки ж сумісні, як і C, якщо ви готові працювати над цим. Як вказує @DeadMG, C ++ підтримує extern "C", так що ви можете експортувати прив'язки до мов стилю C (з усією простотою та сумісністю прив'язок C) з бібліотеки C ++ (з обмеженням, що ви не можете піддавати жодним функціоналам C ++) .
  • Ще одне поширене заперечення щодо прив'язки до мови C ++ - це відсутність стійкості ABI для C ++, але це теж завищено; C ++ ABI менш стандартизовані, ніж C ABI, але стандарти та фактичні стандарти існують (Itanium C ++ ABI, який також використовується в OS X ; фактичний стандарт GCC для Linux). У Windows гірше, але навіть у Windows перебування в одній версії Visual C ++ має працювати добре.

1
Інша проблема із забезпеченням прив'язки бібліотеки C ++ до іншої мови полягає в тому, що інша мова може вимагати виконання прив'язки для C. Або для мов, що мають щось на зразок (.NET) P / Invoke або (python) ctypes, це може не надавати жодних інструментів для використання C ++ ABI.
Випадково832

6
@ Random832: Це абсолютно не має значення, коли сторона C ++ може просто запропонувати інтерфейс C. Вам не потрібно реалізовувати зв'язування в C, щоб запропонувати зв'язування C.
DeadMG

21

C - одна з найдавніших мов, яка все ще існує. Його ABI простий, і практично кожна операційна система, яка досі використовується сьогодні, була написана в ньому . Хоча деякі з цих ОС, можливо, додавали речі, наприклад, у C # /. NET або будь-що інше, внизу вони дуже сильно пронизані C.

Це означає , що для того, щоб використовувати функціональні можливості, що надаються операційною системою, практично кожна мова програмування там потрібен спосіб взаємодії з бібліотеками C в будь-якому випадку . Perl, Java, C ++, всі вони споконвічно пропонують способи "розмовляти з C", тому що їм довелося, якщо вони не хотіли винаходити кожне окреме колесо, що є.

Це робить C латинією мов програмування. (Скільки років Інтернету перед цією метафорою має бути "англійською мовами, що розмовляють"?)


Коли ви пишете свою бібліотеку на мові C, ви отримуєте C-сумісний інтерфейс безкоштовно (очевидно). Якщо ви пишете свою бібліотеку на мові C ++, ви можете отримати прив’язки до C за допомогою extern "C"декларацій, як ви згадували.

Тим НЕ менше , ви можете отримати ці прив'язки тільки для функціональності , які можуть бути виражені в C .

Таким чином, ваш API бібліотеки не може використовувати ...

  • шаблони,
  • класи,
  • винятки,
  • будь-які функції, що приймають або повертають об'єкти.

Один простий приклад, вам потрібно зробити так, щоб експортовані функції брали і повертали масиви ( []) замість std::vector(або std::stringз цього приводу).

Таким чином, ви не тільки не зможете надати будь-які добрі речі, які C ++ може запропонувати клієнтам вашої бібліотеки, а також доведеться докласти додаткових зусиль, щоб "перевести" API своєї бібліотеки з C ++ на "C сумісний" ( extern "C").

Ось чому можна сказати, що C - кращий вибір для впровадження бібліотеки. Особисто я думаю, що переваги C ++ все ще переважають необхідні зусилля для extern "C"API, але це тільки я.


Схоже, Windows намагається базуватися навколо .NET, Android базується на Java (також C як деталь реалізації для деяких API), а iOS / OSX - навколо Objective-C.
користувач253751

1
Англійська мова вже є домінуючою мовою у світі програмування. Більш домінуюче, ніж в інших професіях.
Сіюань Рен

3
@immibis: Windows, Linux / Android та BSD / OSX - всі ядра, написані на C, інтерфейси написані (і для) C. Незалежно від того, що побудовано поверх цього, Java потребує JNI, Perl потребує C дзвінків,. NET потребує C дзвінків, Python потребує C дзвінків, Objective-C потребує C дзвінків. Ніхто з них не потребує дзвінків на C ++, і це я намагався зробити.
DevSolar

@DevSolar Багато речей Android написано спочатку на Java та не використовує JNI (ви можете використовувати його "назад" для виклику коду Java з C, але це ще більше підтверджує, що це спочатку Java). Немає досвіду роботи з iOS / OSX, але я чую, що вони однакові з Objective-C.
користувач253751

3
@immibis: Але ви робите знати різницю між ядром ОС і її призначеним для користувача простором, чи не так? Я серйозно сумніваюся, що в основному користувальницьке середовище Java робить Android менш ядром Linux із системними дзвінками в стилі C, ніж ядро ​​Linux, яке працює на моєму робочому столі. Я також сумніваюся, що вони використовують Java в ядрі або в середньому програмному забезпеченні. Насправді я знаю, що вони там використовують C. Це проблема курей-яєць, просто навпаки. Це робилося в C раніше, і тому так набагато простіше все-таки зробити це в C.
DevSolar

6

Залишаючи деталі, які інші відповіді вже надають:

Причина, по якій багато мов забезпечує прив'язку C, полягає в тому, що всі * nix та операційні системи Windows відкривають більшість своїх API OS через інтерфейс C. Тому мовна реалізація вже потребує взаємодії з C, щоб мати можливість працювати на основних Oses. Тому просто пропонувати також безпосередньо спілкування з будь-яким інтерфейсом С із самої мови.


5

Немає причин. Якщо семантика, яку ви намагаєтеся висловити, є принципово сумісною з C і не є чимось на зразок шаблонів, немає ніяких причин ви можете зв’язувати простіше, якщо реалізація написана в C. Насправді, це майже за визначенням, що інтерфейс C може бути заповнюється будь-якою реалізацією, яка може відповідати двійковому договору, включаючи реалізацію на іншій мові. Існують інші мови, крім C ++, які можуть реалізувати бінарні контракти на C, які можуть працювати таким чином.

На що це дійсно зводиться - це люди, які не хочуть вивчати нові мови чи ідеї, які насправді мають корисну семантику чи особливості, відчайдушно намагаючись вибрати будь-яку причину для перебування в епоху динозавра.


4
Я вважаю, що ви правильні, і спонсори неправильно зрозуміли питання, але насправді ваша відповідь не відповідає, щоб виділити це потенційне непорозуміння: питання не про "бібліотеку з інтерфейсом C" проти "бібліотеку з інтерфейсом C ++", а про "бібліотека, повністю написана на C" проти "бібліотека з інтерфейсом C, написана на C ++".
Док Браун

@Snowman: Проблемні зв'язки C ++ абсолютно не мають нічого спільного з будь-якою проблемою із викриттям зв'язків на C.
DeadMG

2
Отже, ви збираєтесь вибрати мову, яка має корисну семантику та функції, а потім змусити себе перекласти їх на інтерфейс С? Хоча класи та шаблони можуть бути уникнутими (але сумнівайтеся, чому ви використовуєте C ++ в першу чергу), кожна функція зі зв'язуванням C повинна виловлювати винятки, а не дозволяти їм бігти в код C. Не кажучи вже про те, що кожен, хто використовує вашу сумісну з C бібліотекою, тепер має справу з C ++ та його ABI зіткненнями та невідповідностями бібліотеки, крім сутичок ABI субстрату C та невідповідностей бібліотеки.
профілі

2
@prosfilaes: Конвертувати винятки у коди повернення тривіально. Вам не потрібно уникати використання класів, оскільки їх можна легко опустити в API API, і вам не потрібно уникати використання шаблонів у своїй реалізації. І вашим користувачам не потрібно гадати з приводу сутичок C ++ ABI, якщо вони не будуються з джерела, і в цьому випадку вам доведеться мати справу з мовою джерела незалежно від того, що це є.
DeadMG

4
Я прихильнився не тому, що не обов'язково писати бібліотеку з API API в C ++, а тому, що є динамічний привід використовувати C, крім того, щоб бути динозавром. Якщо ви пишете для API мовою X, будьте це C, FORTRAN, COBOL, BLISS або Java, завжди є час, коли простіше, простіше і правильніше писати цією мовою, а потім писати в любителях , більш весела мова та інтерфейс між ними.
профілі

2

При взаємодії з іншою мовою існують дві основні осі:

  • поняття, які інтерфейс може переносити: просто значення? посилання? дженерики?
  • як реалізується інтерфейс у "бінарних файлах" (називається ABI)

C має перевагу над C ++ на цих двох фронтах:

  • C має лише здебільшого прості поняття, які з'являються у більшості інших мов 1
  • ABI з C двійкових файлів визначається ОС 2

Тепер, чому більшість мов мають подібний набір понять, ніж C, можливо, це пояснюється тим, що воно є "простим" або "попереднім"; це не має значення, справа в тому, що вони роблять.

Навпаки, у C ++ є складні поняття, і ABI визначає кожен компілятор (хоча багато хто дотримується Itanimum ABI, за винятком Windows ...). Насправді була пропозиція Herb Sutter, щоб ОС зафіксувала C ++ ABI (на основі ОС), щоб частково вирішити цю проблему. Крім того, слід зазначити, що можливий FFI C ++, D намагається його 3 .

1 За винятком варіантів ( ...), вони не прості

2 Чи має стандартний ABI?

3 З’єднання D з попереднім C ++ кодом


0

По суті це зводиться до стандартизації ABI. Хоча ні C, ні C ++ не мають стандартизованого ABI, який можуть використовувати інші мови для інтерфейсу між записаними двійковими файлами, C став фактичним стандартом, всі знають це, а всі інші можуть використовувати ті самі, прості, правила, якими володіє мова стосовно типи та функціональні дзвінки.

C ++ може мати стандартний ABI, але Stroustrup сказав, що не бачить потреби в цьому. Він також каже, що було б складно досягти консенсусу між авторами-компіляторами (хоча я сумніваюся, що - стандартний комітет C ++ видав би ABI, подібний до існуючого, а автори-компілятори просто змінили б наступну версію своїх компіляторів, яка іноді несумісна з бінарними файлами побудований зі старими версіями їх компіляторів - я пам'ятаю, як перекомпілював пару бібліотек з новим компілятором Sun, і виявив, що вони не змогли працювати зі старими)

Ви зауважите, що деякі компанії перейшли до використання стандартного ABI, Microsoft розпочав цей процес із COM-кодом ще в 90-х роках, і сьогодні вони вдосконалили це в WinRT ABI (не плутати з іншим WinRT, на який йдеться до типу табличної ОС), яка дозволяє програмам, написаним на C #, спілкуватися з бібліотеками, написаними на C або C ++ (тобто власний рівень ОС Microsoft записується на C ++, відкривається за допомогою WinRT та споживається програмами C #, коли вони викликають будь-яку програму виконання ОС)

Ніхто не може зробити багато, якщо орган зі стандартів не вчинить і не виправить цю ситуацію. Microsoft, очевидно, бачить у цьому цінність і вжила заходів для вирішення її для своєї платформи.

Тож відповідь справді C не забезпечує прив’язки до мови. Буває, що ніхто їх не слухав і не вживає.


-2

Усі відповіді не відповідають справжній проблемі: компіляція на C ++ вводить "керування іменами", тому двійкові файли несумісні з "простими" викликами функцій.

Всі речі ABI - це трохи більше, ніж спроба їх стандартизації.

Взагалі це не гарантується, що ви можете перехресно виконувати функції, зібрані з різними компіляторами, навіть якщо ви дотримуєтесь звичайного C ++. Раніше вони були впевнені, що вони несумісні, але нині стандартизація повзає;)

Компанія OTOH C була розроблена саме для того, щоб бути "високою складовою" та дозволяти всіляко взаємодіяти. Це не повинно дивувати, що він краще підходить до міжмовних сподобань.

Побічна примітка: оригінальний компілятор C ++ (cfront) фактично створив джерело C, яке довелося зібрати, точно так само, як gcc, що виробляє збірку "під капотом".

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.