Por que C fornece linguagem 'bindings' onde o C ++ fica aquém?

60

Recentemente eu estava me perguntando quando usar C sobre C ++, e vice-versa? Felizmente alguém já me bateu para ele e, embora demorou um pouco, eu era capaz de digerir todas as respostas e comentários para essa pergunta.

No entanto, um item dessa postagem continua sendo abordado várias vezes, sem nenhum tipo de exemplo, verificação ou explicação:

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

Essa é uma paráfrase. Devo notar que várias pessoas apontam que múltiplas ligações de linguagem são possíveis em C ++ (via algum extern funcionando), mas mesmo assim, se você ler esse post em sua totalidade, é bastante óbvio que C é ideal para portabilidade / ligação de linguagem. Minha pergunta é: por quê?

Alguém pode, por favor, fornecer razões concretas pelas quais escrever bibliotecas em C permite ligações mais fáceis e / ou portabilidade em outros idiomas?

    
por smeeb 04.05.2015 / 12:03
fonte

8 respostas

70

C tem uma interface muito mais simples, e suas regras para converter uma interface de código-fonte em uma interface binária são simples o suficiente para que a geração de interfaces externas para vincular seja feita de maneira bem estabelecida. C ++, por outro lado, tem uma interface incrivelmente complicada, e as regras para a vinculação ABI não são padronizadas, nem formalmente nem na prática. Isso significa que praticamente qualquer compilador para qualquer linguagem de qualquer plataforma pode se ligar a uma interface C externa e saber exatamente o que esperar, mas para uma interface C ++, é essencialmente impossível porque as regras mudam dependendo de qual compilador, qual versão e qual plataforma em que o código C ++ foi construído.

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++

    
por 04.05.2015 / 12:28
fonte
31

Se você está tentando se comunicar com um falante de outro idioma, o pidgin é mais fácil do que o inglês shakespeariano.

Os conceitos de C - chamadas de função, ponteiros, seqüências de caracteres terminadas em NULL - são muito diretos, portanto outras linguagens podem implementá-las facilmente o suficiente para chamar funções em C. Por razões históricas, muitas outras linguagens são implementadas em C, o que torna a chamada de funções C ainda mais fácil.

C ++ adiciona um pouco de coisas - classes, com herança e vtables e modificadores de acesso; exceções, com pilha desenrolando e alterando o fluxo de controle; modelos. Tudo isso torna mais difícil para outras linguagens usar ligações C ++: na melhor das hipóteses, há mais "cola" ou código de interoperabilidade para implementar, e na pior das hipóteses, os conceitos não são traduzidos diretamente (devido a diferenças nos modelos de classe, manipulação de exceção, etc). Para templates em particular, simplesmente usando (instanciando) eles normalmente requerem uma etapa de compilação com um compilador C ++, o que vastamente complica o uso deles de outros ambientes.

Com tudo isso dito, é possível exagerar a dificuldade de fornecer ligações de uma biblioteca C ++ para outro idioma:

  • As ligações de C ++ podem ser tão compatíveis quanto C, se você estiver disposto a trabalhar nisso. Como aponta o @DeadMG, o C ++ suporta extern "C" , portanto você pode exportar ligações de linguagem no estilo C (com toda a simplicidade e compatibilidade de ligações C) de uma biblioteca C ++ (com a limitação de não poder expor nenhum C ++) funcionalidade específica).
  • Outra objeção comum às ligações de linguagem C ++ é a falta de estabilidade ABI para C ++, mas isso também é exagerado; As ABIs C ++ são menos padronizadas do que as C ABIs, mas existem padrões e padrões de fato (o Itanium C ++ ABI, que também é usado no OS X ; Padrão de fato do GCC para Linux). O Windows é pior, mas mesmo no Windows, ficar dentro de uma versão do Visual C ++ deve funcionar bem.
por 04.05.2015 / 14:58
fonte
21

C é uma das línguas mais antigas que ainda existem. Sua ABI é simples, e praticamente todos os sistemas operacionais ainda em uso hoje foram escritos nela . Embora alguns desses sistemas operacionais tenham adicionado itens, por exemplo, em C # /. NET ou o que quer que esteja no topo, embaixo eles estão muito impregnados em C.

Isso significa que, para usar a funcionalidade fornecida pelo sistema operacional, praticamente toda linguagem de programação lá fora precisava de uma maneira de interagir com bibliotecas C de qualquer maneira . Perl, Java, C ++, todos eles nativamente fornecem maneiras de "falar C", porque eles precisavam se não quisessem reinventar cada roda que existe.

Isso faz do C o latim das linguagens de programação. (Quantos anos de internet antes dessa metáfora tem que ser "o inglês de linguagens de programação"?)

Quando você está escrevendo sua biblioteca em C, você obtém uma interface compatível com C de graça (obviamente). Se você está escrevendo sua biblioteca em C ++, você pode obter ligações C, via extern "C" declarações como você mencionou.

No entanto , você pode obter essas ligações somente para a funcionalidade que pode ser expressa em C .

Portanto, a API da sua biblioteca não pode usar ...

  • modelos,
  • aulas,
  • exceções,
  • quaisquer funções levando ou retornando objetos.

Um exemplo simples, você precisaria fazer com que as funções exportadas recebam e retornem arrays ( [] ) em vez de std::vector (ou std::string para isso importa).

Portanto, não só seria incapaz de fornecer as coisas boas que o C ++ tem para oferecer aos clientes da sua biblioteca, como também teria de ir para o esforço adicional para "traduzir" a API da sua biblioteca de C ++ para "C compatible" ( extern "C" ).

É por isso que o ponto poderia ser feito de que C é a melhor escolha para implementar uma biblioteca. Pessoalmente, acho que os benefícios do C ++ ainda superam o esforço necessário para uma extern "C" API, mas isso é só comigo.

    
por 04.05.2015 / 17:15
fonte
6

Deixando de fora os detalhes que outras respostas já fornecem:

A razão pela qual tantos idiomas fornecem uma ligação C é que todos os sistemas operacionais * nix e Windows expõem a maior parte de sua API do SO por meio de uma interface C. Assim, a implementação da linguagem já precisa interagir com o C para poder rodar nos principais Oses. Portanto, é fácil também oferecer comunicação direta com qualquer interface C da própria linguagem.

    
por 04.05.2015 / 16:10
fonte
5

Não há razão. Se a semântica que você está tentando expressar for fundamentalmente compatível com o C e não algo como modelos, não há motivo para você ligar mais facilmente se a implementação for escrita em C. Na verdade, é basicamente por definição que uma interface C pode ser preenchida por qualquer implementação que possa atender ao contrato binário, incluindo uma implementação em outro idioma. Existem outros idiomas além do C ++ que podem implementar contratos binários C que podem funcionar dessa maneira.

O que realmente se resume a pessoas que não querem aprender novas linguagens ou idéias que têm semântica ou recursos realmente úteis, tentam desesperadamente escolher qualquer motivo para permanecer na era dos dinossauros.

    
por 04.05.2015 / 12:17
fonte
2

Existem dois eixos principais na interface com outro idioma:

  • os conceitos que a interface pode transmitir: apenas valores? referências? genéricos?
  • como a interface é implementada em "binários" (chamados ABI)

C tem uma vantagem sobre o C ++ nessas duas frentes:

  • C só tem conceitos simples, que aparecem na maioria das outras línguas 1
  • A ABI dos binários C é decidida pelo OS 2

Agora, por que a maioria dos idiomas tem um conjunto semelhante de conceitos que o C pode ser devido a ele ser "simples" ou "pré-existente"; não importa, porém, o ponto é que eles fazem.

Pelo contrário, o C ++ tem conceitos complexos, e o ABI é decidido por cada compilador (embora muitos adiram ao ITIimum ABI, exceto no Windows ...). Na verdade, houve uma proposta de Herb Sutter para que os sistemas operacionais corrigissem uma ABI C ++ (por sistema operacional) para resolver parcialmente esse problema. Além disso, deve-se notar que uma FFI de C ++ é possível, D está tentando 3 .

1 Exceto os variadics ( ... ), esses não são simples

2 O C tem uma ABI padrão?

3 Conectando D ao código Legacy C ++

    
por 05.05.2015 / 17:41
fonte
0

Fundamentalmente, tudo se resume à padronização da ABI. Embora nem C nem C ++ tenham uma ABI padronizada que outras linguagens possam usar para fazer a interface entre binários escritos, C se tornou um padrão de fato, todo mundo sabe disso e todos os outros podem usar as mesmas regras simples que a linguagem possui em relação a tipos e chamadas de função.

O C ++ poderia ter uma ABI padrão, mas a Stroustrup disse que ele não vê a necessidade de um. Ele também diz que seria difícil obter consenso dos autores de compiladores (embora eu duvide disso - o comitê de padrões C ++ emitirá um ABI similar aos existentes e os compiladores simplesmente alterariam a próxima versão de seus compiladores, que ocasionalmente são incompatíveis com binários construído com versões antigas de seus compiladores de qualquer maneira - eu lembro de recompilar algumas bibliotecas com um novo compilador Sun e descobrir que elas não funcionavam com as antigas)

Você notará que algumas empresas passaram a usar uma ABI padrão, a Microsoft iniciou esse processo com o COM nos anos 90 e hoje elas refinaram isso no WinRT ABI (não confunda com o outro) WinRT que se refere a um tipo de tabela OS) que permite que programas escritos em C # se comuniquem com bibliotecas escritas em C ou C ++ (ou seja, a própria camada do sistema operacional da Microsoft é escrita em C ++, exposta usando WinRT e consumida por aplicativos C # quando eles chamam qualquer tempo de execução do SO rotina)

Não há muita coisa que alguém possa fazer a menos que um corpo de padrões aumente e corrija essa situação. A Microsoft obviamente vê o valor e tomou medidas para resolvê-lo para sua plataforma.

Portanto, a resposta é realmente C não fornece ligações de idioma. Acontece que ninguém os ouviu e consome independentemente.

    
por 06.05.2015 / 10:01
fonte
-2

Todas as respostas ficam aquém do verdadeiro problema: a compilação de C ++ introduz "name mangling", portanto, binários são incompatíveis com chamadas de função "simples".

Todo o material da ABI é pouco mais que uma tentativa de padronizá-lo.

Em geral, não é garantido que você possa fazer ligações cruzadas de funções compiladas com compiladores diferentes, mesmo se você usar o C ++ simples. Antigamente era certo que eles eram incompatíveis, mas hoje em dia a padronização está se infiltrando;)

O OTOH C foi projetado precisamente para ser uma "Montagem de alto nível" e permite todo tipo de interface fácil. Não deve surpreender que seja mais adequado para o gosto entre línguas.

Nota lateral: o compilador C ++ original (cfront) realmente produzia a fonte C que precisava ser compilada, exatamente como o gcc, que produz o Assembly "sob o capô".

    
por 06.05.2015 / 12:04
fonte