Perché C fornisce "binding" di linguaggio in cui il C ++ non è sufficiente?

60

Recentemente mi sono chiesto quando usare C su C ++ e viceversa? fortunatamente qualcuno mi ha già battuto e sebbene ci sia voluto un po 'di tempo, sono riuscito a digerire tutte le risposte e i commenti a quella domanda.

Tuttavia un articolo in quel post continua ad essere indirizzato più e più volte, senza alcun tipo di esempio, verifica o spiegazione:

"C code is good for when you want to have multiple language bindings for your library"

Questa è una parafrasi. Devo notare che diverse persone sottolineano che sono possibili binding in più lingue in C ++ (tramite un po 'di funzionamento di extern ), ma tuttavia, se si legge quel post nella sua interezza, è abbastanza ovvio che C è ideale per la portabilità / linguaggio vincolante. La mia domanda è: perché?

Qualcuno può, per favore, fornire ragioni concrete per cui scrivere in C può semplificare i collegamenti e / o la portabilità in altre lingue?

    
posta smeeb 04.05.2015 - 12:03
fonte

8 risposte

70

C ha un'interfaccia molto, molto più semplice, e le sue regole per convertire un'interfaccia di codice sorgente in un'interfaccia binaria sono abbastanza semplici che la generazione di interfacce esterne per eseguire il binding avviene in modo ben definito. Il C ++, d'altro canto, ha un'interfaccia incredibilmente complicata e le regole per il binding ABI non sono affatto standardizzate, né formalmente né in pratica. Ciò significa che praticamente qualsiasi compilatore per qualsiasi linguaggio per qualsiasi piattaforma può legarsi a un'interfaccia C esterna e sapere esattamente cosa aspettarsi, ma per un'interfaccia C ++, è essenzialmente impossibile perché le regole cambiano a seconda di quale compilatore, quale versione e quale piattaforma con cui è stato creato il codice C ++.

In C, there's no standard binary language implementation rules, either, but it's an order of magnitude simpler and in practice compilers use the same rules. Another reason making C++ code hard to debug is the above-mentioned complicated grammar, since debuggers frequently can't deal with many language features (place breakpoints in templates, parse pointer casting commands in data display windows, etc.).

The lack of a standard ABI (application binary interface) has another consequence - it makes shipping C++ interfaces to other teams / customers impractical since the user code won't work unless it's compiled with the same tools and build options. We've already seen another source of this problem - the instability of binary interfaces due to the lack of compile time encapsulation.

-- Defective C++

    
risposta data 04.05.2015 - 12:28
fonte
31

Se stai cercando di comunicare con un oratore di un'altra lingua, pidgin è più semplice dell'inglese shakespeariano.

I concetti di

C - chiamate di funzioni, puntatori, stringhe con terminazione NULL - sono molto semplici, quindi altri linguaggi possono facilmente implementarli abbastanza bene da chiamare le funzioni C. Per ragioni storiche, molte altre lingue sono implementate in C, il che rende ancora più semplice chiamare le funzioni C.

C ++ aggiunge un bel po 'di roba - classi, con ereditarietà e vtables e modificatori di accesso; eccezioni, con lo stack che si svolge e modifica il flusso del controllo; modelli. Tutto ciò rende più difficile per gli altri linguaggi utilizzare i binding C ++: nella migliore delle ipotesi, c'è più codice "colla" o codice di interoperabilità da implementare, e nel peggiore dei casi i concetti non si traducono direttamente (a causa delle differenze nei modelli di classe, gestione delle eccezioni, eccetera.). Per i template in particolare, semplicemente usando (istanziando) di solito richiede una fase di compilazione con un compilatore C ++, che notevolmente complica usandoli da altri ambienti.

Con tutto ciò detto, è possibile sopravvalutare la difficoltà di fornire collegamenti da una libreria C ++ a un'altra lingua:

  • I collegamenti C ++ possono essere compatibili come C, se sei disposto a lavorarci. Come sottolinea @DeadMG, C ++ supporta extern "C" , quindi puoi esportare i collegamenti linguistici in stile C (con tutta la semplicità e la compatibilità dei collegamenti C) da una libreria C ++ (con la limitazione che non puoi esporre alcun C ++ - funzionalità specifiche).
  • Un'altra obiezione comune ai binding di linguaggio C ++ è la mancanza di stabilità ABI per C ++, ma anche questo è esagerato; Gli ABI C ++ sono meno standardizzati rispetto agli ABI C, ma esistono standard e standard de facto (l'ABI Itanium C ++, che viene anche utilizzato su OS X ; standard GCC di fatto per Linux). Windows è peggio, ma anche su Windows, restare all'interno di una versione di Visual C ++ dovrebbe funzionare correttamente.
risposta data 04.05.2015 - 14:58
fonte
21

C è una delle lingue più antiche ancora in circolazione. Il suo ABI è semplice, e praticamente ogni sistema operativo ancora in uso oggi è stato scritto in esso . Mentre alcuni di questi sistemi operativi potrebbero aver aggiunto roba, ad es. in C # /. NET o qualsiasi cosa sopra, in basso sono molto immersi in C.

Ciò significa che, al fine di utilizzare la funzionalità fornita dal sistema operativo, praticamente ogni linguaggio di programmazione in uscita necessitava comunque di un interfaccia con le librerie C . Perl, Java, C ++, tutti nativamente forniscono dei modi per "parlare C", perché dovevano farlo se non volevano reinventare ogni singola ruota che c'è.

Questo rende C il latino dei linguaggi di programmazione. (Quanti anni di internet prima di quella metafora devono essere "l'inglese delle lingue di programmazione"?)

Quando scrivi la tua libreria in C, ottieni un'interfaccia C-compatibile gratuitamente (ovviamente). Se stai scrivendo la tua libreria in C ++, puoi ottenere i binding C, tramite dichiarazioni extern "C" come hai detto.

Tuttavia , puoi ottenere quei bind solo per la funzionalità che può essere espressa in C .

Quindi l'API della tua biblioteca non può fare uso di ...

  • modelli,
  • classi,
  • eccezioni,
  • tutte le funzioni che prendono o restituiscono oggetti.

Un semplice esempio, dovresti rendere le tue riprese e return matrici esportate ( [] ) invece di std::vector (o std::string per quello materia).

Quindi, non solo non saresti in grado di fornire nessuna delle cose buone che il C ++ ha da offrire ai client della tua biblioteca, dovresti anche andare a ulteriore sforzo per "tradurre" la tua libreria API da C ++ a "C compatibile" ( extern "C" ).

Ecco perché il punto potrebbe essere fatto che C è la scelta migliore per implementare una libreria. Personalmente, penso che i benefici del C ++ superino ancora gli sforzi necessari per un'API extern "C" , ma sono solo io.

    
risposta data 04.05.2015 - 17:15
fonte
6

Tralasciando i dettagli, altre risposte forniscono già:

Il motivo per cui molte lingue forniscono un legame C è che tutti i sistemi operativi * nix e Windows espongono la maggior parte delle API del sistema operativo tramite un'interfaccia C. Quindi l'implementazione della lingua ha già bisogno di interfacciarsi con C per essere in grado di funzionare sui principali Oses. Pertanto, è semplice anche offrire direttamente la comunicazione con qualsiasi interfaccia C dalla lingua stessa.

    
risposta data 04.05.2015 - 16:10
fonte
5

Non c'è motivo. Se la semantica che stai cercando di esprimere è fondamentalmente compatibile con C e non qualcosa come i modelli, non c'è motivo per cui sia possibile legare più facilmente se l'implementazione è scritta in C. Infatti, è per definizione che un'interfaccia C può essere compilata da qualsiasi implementazione in grado di soddisfare il contratto binario, compresa un'implementazione in un'altra lingua. Esistono linguaggi diversi dal C ++ che possono implementare contratti binari C che possono funzionare in questo modo.

Ciò che in realtà si riduce sono le persone che non vogliono apprendere nuove lingue o idee che abbiano semantica o funzionalità utili a cercare disperatamente qualsiasi motivo per rimanere nell'era dei dinosauri.

    
risposta data 04.05.2015 - 12:17
fonte
2

Ci sono due assi principali quando si interfaccia con un'altra lingua:

  • i concetti che l'interfaccia può trasmettere: solo valori? Riferimenti? farmaci generici?
  • come l'interfaccia è implementata in "binari" (chiamata ABI)

C ha un vantaggio rispetto al C ++ su questi due fronti:

  • C ha solo concetti per lo più semplici, che appaiono nella maggior parte delle altre lingue 1
  • I binari ABI of C sono decisi dal sistema operativo 2

Ora, perché la maggior parte delle lingue ha un insieme di concetti simile a quello che potrebbe essere dovuto al fatto che sia "semplice" o "preesistente"; non importa però, il punto è che lo fanno.

Al contrario, C ++ ha concetti complessi e l'ABI è deciso da ciascun compilatore (sebbene molti aderiscano all'ABI di Itanimum, tranne che su Windows ...). C'era in realtà una proposta di Herb Sutter per far sì che i sistemi operativi correggessero un ABI C ++ (su base OS) per risolvere parzialmente questo problema. Inoltre, si dovrebbe notare che è possibile un C ++ FFI, D lo sta tentando 3 .

1 Eccetto variadics ( ... ), quelli non sono semplici

2 C ha un ABI standard?

3 Interfacciamento tra D e il codice C ++ precedente

    
risposta data 05.05.2015 - 17:41
fonte
0

Fondamentalmente si tratta della standardizzazione ABI. Mentre né C né C ++ hanno un ABI standardizzato che altri linguaggi possono usare per interfacciare tra i binari scritti, C è diventato uno standard di fatto, tutti lo sanno e chiunque altro può usare le stesse, semplici regole che il linguaggio ha rispetto a tipi e chiamate di funzione.

C ++ potrebbe avere un ABI standard, ma Stroustrup ha detto che non ne vede la necessità. Dice anche che sarebbe difficile ottenere il consenso dagli autori di compilatori (anche se dubito che - il comitato standard del C ++ emetterebbe un ABI simile a quelli esistenti e gli autori di compilatori semplicemente altererebbero la prossima versione dei loro compilatori, che a volte sono incompatibili con i binari costruito con vecchie versioni dei loro compilatori comunque - Ricordo di aver ricompilato un paio di librerie con un nuovo compilatore Sun e di aver scoperto che non funzionavano con i vecchi)

Noterai che alcune aziende si sono trasferite a utilizzare un ABI standard, Microsoft ha iniziato questo processo con COM negli anni '90 e oggi lo hanno perfezionato nell'ABI WinRT (da non confondere con l'altro WinRT che fa riferimento a un tipo di OS tabella) che consente ai programmi scritti in C # di comunicare con le librerie scritte in C o C ++ (cioè il livello OS di Microsoft è scritto in C ++, esposto usando WinRT e utilizzato dalle applicazioni C # quando chiamano qualsiasi runtime del sistema operativo di routine)

Non c'è molto che chiunque può fare a meno che un corpo standard non si evolva e risolva questa situazione. Microsoft ovviamente ne vede il valore e ha preso provvedimenti per risolverlo per la loro piattaforma.

Quindi la risposta è in realtà C non fornisce collegamenti linguistici. Succede che nessuno li ha ascoltati e li consuma a prescindere.

    
risposta data 06.05.2015 - 10:01
fonte
-2

Tutte le risposte non rispondono al vero problema: la compilazione in C ++ introduce "nome mangling", quindi i binari non sono compatibili con le chiamate di funzione "semplici".

Tutta la roba ABI è poco più di un tentativo di standardizzarlo.

In generale non è garantito che sia possibile eseguire il cross-link delle funzioni compilate con diversi compilatori, anche se ci si attiene al semplice C ++. Precedentemente era sicuro che erano incompatibili, ma al giorno d'oggi la standardizzazione si sta insinuando;)

OTOH C è stato progettato proprio per essere un "Assemblaggio di alto livello" e consente qualsiasi tipo di interfaccia facile. Non dovrebbe sorprendere che sia più adatto al linguaggio cross-like.

Nota a margine: il compilatore C ++ originale (cfront) ha effettivamente prodotto una sorgente C che doveva essere compilata, esattamente come gcc che produce Assembly "under the hood".

    
risposta data 06.05.2015 - 12:04
fonte

Leggi altre domande sui tag