O C ++ é adequado para sistemas embarcados?


168

Uma pergunta comum, aqui e em outros lugares. O C ++ é adequado para sistemas embarcados?

Microcontroladores? RTOSes? Torradeiras? PCs incorporados?

OOP é útil em microcontroladores?

O C ++ remove o programador muito longe do hardware para ser eficiente?

O C ++ do Arduino (sem gerenciamento dinâmico de memória, modelos, exceções) deve ser considerado como "C ++ real"?

(Espero que este wiki sirva como um local para conter essa guerra santa em potencial)


5
Pergunta rápida: quando você diz incorporado , você quer dizer microcontrolador? microprocessador? x86 / PC incorporado?
precisa

1
Eu não pretendia causar uma guerra santa; a intenção era descobrir quais eram seus argumentos contra isso.
precisa

2
Ele já apareceu em várias perguntas antes, então pensei que um lugar central seria bom.
Toby Jaffey

4
C ++ vs incorporado é um tópico controverso. Tenho uma opinião forte, mas não achei justo fazer uma pergunta e jogar em pontos de pontuação. Espero que um wiki da comunidade contribua para uma discussão mais equilibrada.
precisa saber é o seguinte

13
Essa é uma pergunta ruim, pois "incorporado" é um atributo sem sentido para decidir se um idioma específico e sua bagagem associada são adequados. O ponto é pequeno versus sistemas grandes, onde sistemas pequenos não estão executando um sistema operacional, têm memória limitada, podem não ser von-Neuman, podem ter várias restrições de hardware em pilhas de chamadas, pilhas de dados, você não pode alocar dinamicamente um Mb ou mesmo um kb, etc. A maioria dos microcontroladores são sistemas "pequenos". Os computadores de placa única geralmente são incorporados, mas geralmente são sistemas "grandes".
precisa

Respostas:


135

Sim, o C ++ ainda é útil em sistemas incorporados. Como todo mundo já disse, ainda depende do sistema em si, como um uC de 8 bits provavelmente seria um não-não no meu livro, embora exista um compilador por aí e algumas pessoas o façam (estremecem). Ainda há uma vantagem em usar C ++, mesmo quando você o reduz para algo como "C +", mesmo em um micro mundo de 8 bits. O que quero dizer com "C +"? Quero dizer, não use new / delete, evite exceções, evite classes virtuais com herança, possivelmente evite a herança todos juntos, tenha muito cuidado com os modelos, use funções embutidas em vez de macros e use constvariáveis ​​em vez de #defines.

Trabalho com C e C ++ em sistemas embarcados há mais de uma década, e parte do meu entusiasmo juvenil por C ++ definitivamente desapareceu devido a alguns problemas do mundo real que abalam a ingenuidade. Vi o pior do C ++ em sistemas embarcados aos quais gostaria de me referir como "programadores de CS enlouquecidos em um mundo de EE". Na verdade, é nisso que estou trabalhando com meu cliente para melhorar essa base de código que eles têm, entre outros.

O perigo do C ++ é porque é uma ferramenta muito poderosa, semelhante a uma espada de dois gumes que pode cortar tanto seu braço quanto sua perna se não for educada e disciplinada adequadamente em sua linguagem e programação geral. C é mais como uma faca de um gume, mas ainda é tão afiada. Com o C ++, é muito fácil obter altos níveis de abstração e criar interfaces ofuscadas que se tornam sem sentido a longo prazo, e isso se deve em parte à flexibilidade do C ++ em resolver o mesmo problema com muitos recursos de linguagem diferentes (modelos, OOP, procedurais, Modelos RTTI, OOP +, sobrecarga, embutimento).

Eu terminei dois seminários de 4 horas sobre software embarcado em C ++ pelo guru do C ++, Scott Meyers. Ele apontou algumas coisas sobre modelos que eu nunca considerei antes e quanto mais elas podem ajudar a criar código crítico de segurança. O ponto principal é que você não pode ter código morto em software que precisa atender a requisitos rigorosos de código crítico de segurança. Os modelos podem ajudá-lo a fazer isso, pois o compilador cria apenas o código necessário ao instanciar modelos. No entanto, é preciso tornar-se mais instruído em seu uso para projetar corretamente esse recurso, mais difícil de ser realizado em C, porque os vinculadores nem sempre otimizam o código morto.

Scott Meyers é um grande defensor de modelos e uso criterioso de inlining, e devo dizer que ainda estou cético em ser entusiasmado com modelos. Eu costumo me afastar deles, mesmo que ele diga que eles devem ser aplicados apenas quando se tornarem a melhor ferramenta. Ele também enfatiza que o C ++ fornece as ferramentas para criar interfaces realmente boas, fáceis de usar corretamente e que dificultam o uso errado. Novamente, essa é a parte mais difícil. É preciso chegar a um nível de domínio em C ++ antes que você possa saber como aplicar esses recursos da maneira mais eficiente possível para ser a melhor solução de design.

O mesmo vale para OOP. No mundo incorporado, você deve se familiarizar com o tipo de código que o compilador vai cuspir para saber se pode lidar com os custos de tempo de execução do polimorfismo em tempo de execução. Você também deve estar disposto a fazer medições para provar que seu projeto atende aos requisitos de prazo. Essa nova classe InterruptManager tornará minha latência de interrupção muito longa? Existem outras formas de polimorfismo que podem se encaixar melhor no seu problema, como o polimorfismo em tempo de link, que C também pode fazer, mas o C ++ pode fazer através do padrão de design Pimpl (ponteiro opaco) .

Eu digo o suficiente para dizer que o C ++ tem seu lugar no mundo incorporado. Você pode odiar tudo o que quiser, mas não vai embora. Ele pode ser escrito de uma maneira muito eficiente, mas é mais difícil aprender como fazê-lo corretamente do que com C. Às vezes, pode funcionar melhor que C na solução de um problema e, às vezes, na expressão de uma interface melhor, mas, novamente, você precisa eduque-se e não tenha medo de aprender como.


1
Isso está alinhado com o que li de outros consultores de sistemas embarcados. Sempre fui ensinado que, com C, você se corta de pequenas maneiras constantemente, mas um bug no C ++ será mais raro, mas quando você estraga tudo, perde uma perna. Obrigado por escrever uma resposta clara com alguns conhecimentos que não tenho.
Kortuk

3
Na nota dos cursos de Ciência da Computação enlouquecendo na terra dos EE. No meu trabalho, o pior código que temos foi escrito por um especialista em CS. Passamos uma eternidade tentando ensinar a ele qual era o hardware. Ele criou um sistema estruturado usando UML e construiu todo o sistema baseado em java, usando herança adequada e assim por diante. Funcionou até que tudo mudou e, em seguida, foi um trabalho ruim de patch adicionar recursos ou um redesenho completo. O código quase não é utilizável por causa de quão completamente ele ofuscou a coisa toda com herança.
Kortuk

2
Não são apenas os erros que o mordem, mas o código não sustentável que também o morderá. Claro, quando você inicia esse projeto usando esses recursos puros do C ++, tudo corre bem, mas após 2 ou 3 anos a entropia entra em ação se nenhum esforço sério for feito na refatoração à medida que você desenvolve. É isso que estou enfrentando agora ... o código apodrece mais rápido ao longo do tempo em C ++.
Jay Atkinson

2
UML e máquinas de estado. Você realmente precisa dar uma olhada nas coisas de Miro Samek em state-machine.com . Ele construiu um sistema eficiente que é fácil de refatorar e alterar, mas leva algum tempo para ser entendido.
Jay Atkinson

2
Realmente depende do seu sistema e quanta memória você tem disponível. Você está escrevendo código em um micro de 8 bits com muito pouca RAM? Então é melhor evitar enlouquecer em interfaces abstratas. Se você estiver escrevendo algo como sistemas embarcados de 32 bits com placas de memória, faça isso. Você realmente tem que pesar. Por exemplo, toda vez que você coloca o mundo "virtual" nessa classe, recebe um ponteiro extra, que pode ser de 8 bits, 16 bits ou 32 bits, dependendo do sistema, para cada instância que você declara desse objeto. Você nem vai perceber, e o homem,
Jay Atkinson

56

C ++ é absolutamente adequado para sistemas embarcados. Agora uso a presença / ausência de boas ferramentas de desenvolvimento (ou a falta delas) como meu principal critério para usar ou não um microprocessador específico.

Áreas de C ++ que são boas de usar em sistemas incorporados porque possuem baixos custos de recursos:

  • modularidade trazida pelo bom uso de classes / estruturas
  • modelos se o compilador fizer um bom trabalho compilando-os com eficiência. Os modelos são uma boa ferramenta para trazer a reutilização de algoritmos para diferentes tipos de dados.

Áreas OK:

  • funções virtuais - eu costumava ser contra isso, mas o custo do recurso é muito pequeno (uma tabela de tabelas por classe , não por objeto; um ponteiro para a tabela de tabelas por objeto; uma operação de cancelamento de referência por chamada de função virtual) e a grande vantagem disso é que permite que você tenha uma matriz contendo vários tipos diferentes de objetos sem ter que saber qual é o tipo. Eu usei isso recentemente para ter uma matriz de objetos, cada um representando um dispositivo I2C, cada um com métodos separados.

Áreas a não usar, principalmente por causa da sobrecarga de tempo de execução que é inaceitável em pequenos sistemas:

  • alocação dinâmica de memória - outros já mencionaram isso, mas outro motivo importante para não usar a alocação dinâmica de memória é que ela representa incerteza no tempo; muitas razões para usar sistemas incorporados são para aplicativos em tempo real.
  • RTTI (informações sobre o tipo de tempo de execução) - o custo da memória é bastante grande
  • exceções - um não-não definitivo , devido à velocidade de execução atingida

Obrigado pela contribuição. Interessante e muito parecido com o que eu li.
Kortuk

1
A alocação de memória realmente dinâmica é boa e às vezes inevitável. É a memória dinâmica DEallocation (e subsequente reutilização) que é o problema. RTTI é porco da memória, eu concordo com isso. Mas qual é o problema com exceções?
Wouter van Ooijen

1
@WoutervanOoijen: O problema das exceções é que, se as foochamadas bardentro de um bloco try/ criam alguns objetos e chamadas , o que gera uma exceção, o sistema precisa, de alguma forma, chamar os destruidores dos objetos criados antes de retornar o controle . A menos que as exceções sejam completamente desabilitadas, não haverá como saber se pode lançar alguma e, portanto, deve incluir código extra para permitir essa possibilidade. Eu gostaria de ver uma variação do C ++ com "exceções verificadas" para lidar com isso; se rotinas que poderiam permitir que exceções escapem ... #catchbarbozbarfoobarboz
317

1
... tinha que ser declarado como tal, seria necessário apenas que o compilador incluísse o código de tratamento de exceções nos chamadores de tais rotinas. Certamente, ter que adicionar todas as declarações necessárias, evitando as desnecessárias, seria um pouco oneroso, mas permitiria que exceções fossem usadas em locais onde são úteis, sem acrescentar sobrecarga onde não estão.
precisa

3
@WoutervanOoijen: Aliás, se eu estivesse projetando a ABI para esse tratamento de exceção no ARM, especificaria que o código que chama uma rotina que pode sair por exceção deve ter R14 apontar para um endereço dois bytes antes do endereço de retorno desejado (isso seria ocorrer naturalmente se o chamador seguiu a instrução CALL com uma palavra de 16 bits). A rotina chamada sairia normalmente via em add r15,r14,#2vez de mov r15,r14; para sair por exceção ldrhs r0,[r14] / add r15,r14,r0. Custo de ciclo zero para a saída normal e sem restrições de estrutura de pilha.
Supercat

36

Sim, C ++ é certamente adequado para sistemas embarcados. Primeiro, vamos esclarecer alguns conceitos errados sobre a diferença entre C e C ++:

Em um micro incorporado, você sempre precisará usar linguagens de alto nível com cuidado se estiver preocupado com as restrições de tempo ou espaço. Por exemplo, muitos MCUs não lidam bem com ponteiros e, portanto, são muito ineficientes ao usar a pilha. Isso significa que você deve ter cuidado ao passar variáveis ​​para funções, usando matrizes e ponteiros e recursão. Uma linha simples de C como:

a[i] = b[j] * c[k];

pode gerar cerca de 4 páginas de instruções, dependendo da natureza dessas variáveis.

Sempre que você estiver usando qualquer idioma de alto nível e estiver preocupado com as restrições de tempo e espaço, precisará saber como cada recurso desse idioma se traduz em instruções de máquina no seu MCU (pelo menos, todos os recursos que você usa). Isso é verdade para C, C ++, Ada, qualquer que seja. Provavelmente todos os idiomas conterão recursos que não são traduzidos eficientemente em pequenas MCUs. Sempre verifique as listas de desmontagem para garantir que o compilador não esteja gerando resmas de instruções para algo trivial.

C é adequado para MCUs incorporadas? Sim, desde que você fique de olho no código gerado.
O C ++ é adequado para MCUs incorporadas? Sim, desde que você fique de olho no código gerado.

Eis por que acho que o C ++ é melhor que o C, mesmo em MCUs de 8 bits: O C ++ fornece suporte aprimorado para:

  • Ocultar dados
  • Digitação / verificação mais fortes
  • Transparência multi-periférica usando classes
  • Modelos (como sempre, se usados ​​com cuidado)
  • Listas de inicialização
  • const

Nenhum desses recursos é mais pesado que os recursos típicos de C.

À medida que você move MCUs de 16 ou 32 bits, começa a fazer sentido usar recursos mais pesados ​​de C (pilha, pilha, ponteiros, matrizes, printf etc.) Da mesma forma, um MCU mais poderoso é apropriado. para usar recursos mais pesados ​​do C ++ (pilha, pilha, referências, STL, novo / excluir).

Portanto, não há necessidade de estremecer ao pensar em C ++ em um PIC16. Se você conhece seu idioma e seu MCU corretamente, saberá como usá-los de maneira eficaz juntos.


3
Esta é uma resposta muito bem expressa e razoável à pergunta. +1 Saúde!
vicatcu

1
" a[i] = b[j] * c[k];pode gerar cerca de 4 páginas de instruções, dependendo da natureza dessas variáveis." Se o seu MCU / compilador faz isso, é porque você está usando alguma CPU hobbyista de garagem dos anos 80.
Lundin 4/15

@Lundin - Suspiro. Não, isso significa que você está usando um pequeno MCU barato, projetado para ser o menor e o mais barato possível, para não ter coisas complexas, como indexação de pilha.
precisa

2
@Rocketmagnet Ok, talvez nos anos 90? Atualmente, os 8 bitters de baixa qualidade têm o mesmo preço dos 32 bitters. A única razão que resta para escolher o primeiro é o consumo atual. E com relação aos 8 bits de baixa qualidade e sem pilha: se você escreve C em vez de assembler para um MCU tão limitado, provavelmente está fazendo algo errado. As 4 páginas geradas são sua culpa por escrever programas muito complexos para a CPU e, essencialmente, C é a ferramenta errada para a tarefa. (Eu tenho feito isso no passado em Freescale RS08, que era uma ideia muito estúpida.)
Lundin

O processador @Lundin de 32 bits não é necessário mais rápido que 16 bits. Isso era evidente no tempo em que a transição do programa de 16 para 32 bits estava ocorrendo no mundo dos PCs.
Barleyman

24

Eu sempre acho esses debates divertidos de ler. Não tanto para a discussão intelectual sobre os prós e contras dos vários idiomas disponíveis, mas porque geralmente você pode identificar a posição de alguém no tópico com base em seu trabalho / experiência / área de interesse. Está aí em cima, com os argumentos de "otimização prematura", onde os principais especialistas em CS e os programadores de manutenção citam Knuth à esquerda e à direita e aqueles que trabalham no mundo real onde questões de desempenho acham que são loucos (sou membro do último grupo) para ser justo).

No final do dia, você pode desenvolver um excelente software em C ou C ++ ou inserir a linguagem aqui . Tudo se resume aos recursos do desenvolvedor, não ao idioma. Ser um especialista em um idioma geralmente é necessário apenas se você escolheu o idioma errado e agora precisa se empenhar para resolver seu problema. Na maioria dos casos, essas são as únicas situações em que você precisa mergulhar em recursos ou compiladores obscuros truques para atingir o objetivo.

Costumo ouvir as pessoas iniciarem esses argumentos como "sou especialista na linguagem X e blá blá". Sinceramente, imediatamente desacredito essas pessoas porque, na minha opinião, elas já abordaram o problema pelo ângulo errado e tudo o que foi contaminado pelo desejo de usar sua ferramenta para resolver o problema e mostrar como é "legal".

Costumo observar os desenvolvedores escolherem primeiro um conjunto de ferramentas e tentarem resolvê-lo em segundo lugar, o que está completamente errado e resulta em soluções ruins.

Como mencionei em um comentário para outra resposta, essas guerras de linguagem frequentemente se baseiam em argumentar que a linguagem X permite que o programador faça coisas mais idiotas. Embora seja divertido ler, todas essas declarações realmente significam é que você tem um problema ao contratar bons desenvolvedores e precisa resolver esse problema diretamente, em vez de tentar ajudar a situação, continuando a contratar maus desenvolvedores e escolhendo ferramentas para que eles possam fazer o mínimo possível. dano possível.

Na minha opinião, bons desenvolvedores, sejam eles de software ou hardware, pesquisam o problema, arquitetam uma solução e encontram as ferramentas que lhes permitem expressar a solução da "melhor maneira". Não importa se a ferramenta necessária é algo que você nunca usou antes, depois de usar 3-4 ferramentas de idiomas / desenvolvimento para projetos que escolhem uma nova ferramenta que tenha um impacto mínimo no tempo de desenvolvimento.

Obviamente, 'melhor caminho' é um termo subjetivo e também precisa ser definido na fase de pesquisa. É preciso considerar uma infinidade de questões: desempenho, facilidade de expressão, densidade de código etc. com base no problema em questão. Não incluí a manutenção nessa lista por um motivo, não me importo com o idioma que você escolher, se você escolheu a ferramenta adequada e gastou um tempo para entender o problema, isso deve vir "de graça". A manutenção difícil do código geralmente resulta da escolha da ferramenta errada ou de uma estrutura de sistema ruim; isso resulta em uma bagunça hacky feia para fazê-lo funcionar.

Reivindicar qualquer idioma é "melhor" do que qualquer outro é tolo sem definir um problema de interesse específico. Uma abordagem orientada a objetos nem sempre é melhor que uma abordagem funcional. Existem alguns problemas que se prestam muito bem a um paradigma de design orientado a objetos. Há muitos que não. A mesma afirmação pode ser feita sobre muitos recursos de linguagem que as pessoas parecem gostar de usar.

Se você está gastando mais de 20% do seu tempo em um problema de digitação de código, provavelmente está produzindo um sistema muito ruim ou tem desenvolvedores muito ruins (ou ainda está aprendendo). Você deve gastar a maior parte do seu tempo antecipadamente diagramando o problema e determinando como várias partes do aplicativo interagem. Colocar um grupo de desenvolvedores talentosos em uma sala com uma placa de marcador e um problema para resolver e dizer a eles que não têm permissão para escrever nenhum código ou escolher nenhuma ferramenta até que se sintam confortáveis ​​com todo o sistema fará mais para melhorar a qualidade do produção e velocidade de desenvolvimento do que escolher qualquer nova ferramenta quente garantida para melhorar o tempo de desenvolvimento. (procure o desenvolvimento scrum como uma referência para o oposto polar ao meu argumento)

Muitas vezes, a triste realidade é que muitas empresas só podem medir o valor de um desenvolvedor pelo número de linhas escritas ou vendo 'saída tangível'. Eles veem as 3 semanas em uma sala com um quadro de marcadores como uma perda de produtividade. Os desenvolvedores geralmente são forçados a acelerar o estágio de "pensamento" do desenvolvimento ou são forçados a usar uma ferramenta definida por algum problema político da empresa: "O irmão do meu chefe trabalha para a IBM, para que possamos usar apenas suas ferramentas", esse tipo de lixo . Ou pior, você obtém um conjunto de requisitos em constante mudança da empresa, porque eles não são capazes de fazer uma pesquisa de mercado adequada ou não entendem o impacto das mudanças no ciclo de desenvolvimento.

Desculpe por estar um pouco fora do tópico com este discurso retórico, tenho opiniões bastante fortes sobre esse tópico.


2
Agora, não estou testando os testes de unidade no nível do aplicativo (acima do driver) em certos sistemas embarcados. Há algum valor no feedback instantâneo de testes de unidade e remoção de bugs no início da fase de desenvolvimento, mas todo o paradigma TDD para dar à luz o design me parece um pouco tonto. Prefiro levar algum tempo para "pensar" sobre o problema e diagrama-lo na minha cabeça, no papel ou em um quadro branco, antes de começar a codificar. Eu também acho que o TDD incentiva o mercado a não fazer pesquisas iniciais sobre requisitos, porque ele deve ajudar com a constante mudança de requisitos.
Jay Atkinson

2
E para colocar uma nota final no meu comentário super longo. Não precisamos de especialistas em idiomas para trabalhar no design. Precisamos de designers especializados que possam trabalhar o (s) idioma (s).
Jay Atkinson

1
PRD = documento de requisitos do produto, MRD = documento de requisitos de marketing, TRD = documento de requisitos técnicos. TDD = Desenvolvimento Orientado a Testes.
Jay Atkinson

1
@ Mark - Eu concordo com seus sentimentos de design inicial, mas apenas até certo ponto. Eu acho que trabalhos pesados ​​de design adiantado compensa se: a) seus requisitos são razoavelmente estáveis ​​/ conhecidos eb) os desenvolvedores que fazem o design são experientes . Em um prev. trabalho, fui incumbido de fazer um design e ele foi muito organizado pelo chefe da minha equipe e pensei: "Que coisa idiota de se fazer! O design inicial economiza dinheiro (consulte o livro Código completo)?" Mas, na codificação, descobri toneladas de coisas que não sabia procurar. Se eu tivesse feito muito design e minimizado o tempo de código, teria sido um desperdício. JME.
J. Polfer

1
@sheepsimulator Obviamente, eu concordo com o segundo ponto, presumo que os arquitetos líderes de sistemas são desenvolvedores experientes. No primeiro ponto, eu realmente discordo. Acho que quanto mais você espera que os requisitos mudem, mais tempo deve gastar na fase de design, porque você precisa produzir um design bom e fácil de mudar. Eu sei que algumas filosofias propõem um desenvolvimento rápido. Em alguns casos, isso funciona bem como muitos programadores ruins ou inexperientes na equipe. Todas essas filosofias de design se resumem a dizer "não tenho oração para projetar um sistema flexível; portanto, não perca tempo tentando".
Mark

17

Qualquer idioma pode ser adequado para um sistema incorporado. Incorporado significa apenas: parte de um aparelho maior, em oposição a um computador de uso livre.

A pergunta tem mais relevância quando solicitada por um sistema (difícil) em tempo real ou de recursos limitados .

Para um sistema em tempo real, o C ++ é uma das linguagens mais altas que ainda é apropriada na programação de restrições de tempo rigorosas. Com exceção do uso de heap (operador livre), ele não possui construções com tempo de execução indeterminado, para que você possa testar se o seu programa atende aos requisitos de tempo e, com um pouco mais de experiência, pode até prever. Evidentemente, o uso de heap deve ser evitado, embora o novo operador ainda possa ser usado para alocação única. As construções que o C ++ oferece sobre o C podem ser bem utilizadas em um sistema incorporado: OO, exceções, modelos.

Para sistemas com recursos muito limitados (chips de 8 bits, menos de alguns Kb de RAM, sem pilha acessível), o C ++ completo pode ser inadequado, embora ainda possa ser usado como um 'C melhor'.

Eu acho lamentável que Ada pareça ser usado apenas em alguns nichos. De muitas maneiras, é um Pascal ++, mas sem o ônus de ser compatível com uma linguagem que já era uma bagunça séria para começar. (editar: a bagunça séria é, naturalmente, C. Pascal é uma linguagem bonita, mas um tanto impraticável.)

==================================================== ==============

EDIT: Eu estava digitando uma resposta para a nova pergunta ("Em quais casos o C ++ é necessário quando estamos programando microcontroladores"?) Que foi fechado com referência a esta, então adicionarei o que escrevi:

Nunca existe uma razão absoluta para o uso de qualquer linguagem de programação, mas pode haver argumentos que têm mais ou menos peso em uma situação específica. Discussões sobre isso podem ser encontradas em muitos lugares, com posições que variam de "nunca use C ++ para um microcontrolador" a "sempre use C ++". Eu sou mais com a última posição. Posso dar alguns argumentos, mas você terá que decidir por si próprio quanto peso eles têm em uma situação específica (e em que direção).

  • Compiladores C ++ são mais raros que compiladores C; para alguns destinos (por exemplo, PICs principais de 12 e 14 bits), não existem compiladores C ++.
  • (bons) programadores de C ++ são mais raros do que (bons) programadores de C, especialmente entre aqueles que também são (um pouco) conhecedores de eletrônica.
  • O C ++ possui mais construções que o C que não são apropriadas para sistemas pequenos (como exceções, RTTI, uso frequente do heap).
  • O C ++ possui um conjunto mais rico de bibliotecas (padrão) que o C, mas uma consequência do ponto anterior é que as bibliotecas C ++ costumam usar recursos inapropriados para sistemas pequenos e, portanto, não são utilizáveis ​​em sistemas pequenos.
  • O C ++ possui mais construções que o C que permitem que você atire no próprio pé.
  • O C ++ possui mais construções que o C que permitem impedir que você se atire no pé (sim, na IMO, isso e o anterior são verdadeiros).
  • O C ++ possui um conjunto mais rico de mecanismos de abstração, permitindo melhores formas de programação, especialmente para bibliotecas.
  • Os recursos da linguagem C ++ (por exemplo, construtores / destruidores, funções de conversão) tornam mais difícil ver através do código a máquina gerada e, portanto, o custo no espaço e no tempo de uma construção de linguagem.
  • A construção da linguagem C ++ torna menos necessário estar ciente de como exatamente eles são traduzidos para o código de máquina, porque eles fazem a coisa certa de uma maneira mais abstrata.
  • O padrão da linguagem C ++ está evoluindo rapidamente e é adotado rapidamente pelos grandes compiladores (gcc, clang, microsoft). C está evoluindo de maneira bastante lenta, e a adoção de alguns recursos mais recentes (matrizes variantes) é assustadora e até mesmo foi revertida em um padrão posterior. Este ponto em particular é interessante porque pessoas diferentes o usam para apoiar posições opostas.
  • O C ++ é sem dúvida uma ferramenta mais nítida que a do C. Você confia nos seus programadores (ou em si mesmo) para usar essa ferramenta para fazer uma bela escultura, ou você tem medo que eles se machuquem e você prefere optar por um produto menos bonito, mas de baixo risco ? (Lembro-me de que meu professor de escultura me disse uma vez que em algumas situações as ferramentas bruscas podem ser mais perigosas que as afiadas.)

Meu blog tem alguns escritos sobre o uso de C ++ em pequenos sistemas (= microcontroladores).


15

Na minha experiência, o C ++ geralmente não é adequado para pequenos sistemas embarcados. Com o que quero dizer, microcontroladores e dispositivos sem SO.

Muitas técnicas de C ++ OOP contam com alocação dinâmica de memória. Isso geralmente está ausente em pequenos sistemas.

STL e Boost realmente demonstram o poder do C ++, ambos são enormes em tamanho.

O C ++ incentiva o programador a abstrair a máquina, onde em sistemas restritos ela deve ser adotada.

No ano passado, eu levei um produto comercial de desktop remoto para telefones móveis. Foi escrito em C ++ e rodou em Windows, Linux e OSX. Mas, dependia bastante de STL, memória dinâmica e exceções de C ++. Para rodar em ambientes WinCE, Symbian e sem SO, uma reescrita em C era a opção mais segura.


Concordo em referência a pequenos sistemas, mas acho que temos diferentes definições de pequenos sistemas. Quando você tem 1kB de ROM e um código C bem escrito, leva apenas 1 byte de ROM, que é um sistema pequeno.
Kortuk

6
Eu não estou argumentando que C não pode ter uma área menor, mas você poderia ter usado C ++ ainda e obter um resultado muito semelhante ao projetar para o que acabamos de discutir. Eu acho que o problema é que a maioria dos programadores de OOP está acostumada a sistemas com memória dinâmica e usando construções muito ineficientes, resultando em código completamente inútil para sistemas de menor potência.
Kortuk

4
então, o que você está dizendo é que você não deseja usar C ++, deseja usar algo entre C e C ++ (vamos chamá-lo de C ++?). Nesse caso, eu concordo, há muita porcaria em C ++ que as pessoas usam apenas porque estão disponíveis, não porque são ótimas. Quase qualquer linguagem é capaz de produzir código bom e rápido, é uma questão de como é usada. A maioria das guerras santas mais línguas não são resultado das capacidades de línguas, mas uma discussão sobre como é fácil para um idiota para fazer coisas idiotas, o que é um argumento idiota realmente: p
Mark

2
"A maioria das guerras sagradas sobre as línguas não é resultado das capacidades linguísticas, mas uma discussão sobre como é fácil para um idiota fazer coisas idiotas, o que é realmente um argumento idiota". Foi uma frase muito agradável. Preciso do seu sobrenome para que eu possa citar esse.
Kortuk

1
Eu realmente não uso a memória dinâmica em C também. Não há nenhum lugar que eu tenho que ter. A longo prazo, li que ele pode ser muito, muito segmentado e começar a causar problemas. Preciso ter casos claramente projetados para ficar sem memória e preciso monitorar exatamente quanto resta.
Kortuk

11

Espero acrescentar mais luz do que calor a essa discussão sobre C ++ em sistemas bare metal e com recursos limitados.

Problemas em C ++:

  • As exceções são especialmente um problema de RAM, pois o "buffer de emergência" necessário (onde a exceção de falta de memória ocorre, por exemplo) pode ser maior que a RAM disponível e certamente é um desperdício para os microcontroladores. Para mais informações, consulte n4049 e n4234 . Eles devem ser desativados (que atualmente é um comportamento não especificado, portanto, certifique-se e nunca jogue). Atualmente, o SG14 está trabalhando em melhores maneiras de fazer isso.

  • RTTI provavelmente nunca vale a pena a sobrecarga, deve ser desativado

  • Compilações grandes de depuração, embora isso não seja um problema no desenvolvimento clássico de área de trabalho, se a depuração não couber no chip, pode ser um problema. O problema surge do código de modelo ou de chamadas de funções extras adicionadas para maior clareza. Essas chamadas de funções extras serão removidas novamente pelo otimizador e a clareza ou flexibilidade adicional pode ser uma grande vantagem; no entanto, nas compilações de depuração, isso pode ser um problema.

  • Alocação de pilha. Embora o STL permita o uso de alocadores personalizados, isso pode ser complexo para a maioria dos programadores. A alocação de heap não é determinística (ou seja, não é em tempo real) e a fragmentação pode levar a situações inesperadas de falta de memória, apesar de ter trabalhado nos testes. A manutenção de livros necessária à pilha para controlar o espaço livre e o tamanho variável pode ser um problema com objetos pequenos. Geralmente é melhor usar a alocação de pool (tanto em C quanto em C ++), mas isso pode ser anormal para os programadores de C ++ que costumavam usar apenas o heap.

  • O polimorfismo de tempo de execução e outras chamadas indiretas geralmente são um grande problema de desempenho, o problema geralmente é maior porque o otimizador não pode ver através deles mais do que a busca e o salto reais para o endereço. Chamadas indiretas devem ser evitadas por esse motivo em C e C ++, onde, como em C ++, elas estão mais arraigadas na cultura (e são bastante úteis em outros domínios).

  • A interface implícita com o clib pode ser problemática. Pode ser contra-intuitivo que os problemas de clib estejam na categoria C ++, mas o problema surge do compartilhamento implícito de recursos em ambientes simultâneos (o compartilhamento é mais explícito em C). O uso da implementação comum do newLib costuma arrastar muito inchaço, o que geralmente não é necessário nos UCs, por outro lado, o newLibNanno não é reentrante, portanto, o acesso a ele deve ser serializado (simplificando demais aqui). Isso também é um problema para C, mas o acesso é mais explícito. Como regra geral, não se deve essencialmente usar nada do namespace std no contexto ISR, a menos que você tenha certeza de que não acessa o estado no clib de alguma forma (errorno ou o heap, por exemplo). Também é importante se você estiver usando threads (prefiro o RTC) para substituir new e delete para sincronizar o acesso ao malloc e ao free.

Em conclusão, o C ++ tem alguns problemas, mas eles são essencialmente todos corrigíveis ou evitáveis.

Agora para C, aqui o problema é de ordem superior. Eu não tenho a capacidade sintática em C para abstrair as coisas de uma maneira que eu possa executar otimização ou verificar invariantes em tempo de compilação. Portanto, não consigo encapsular adequadamente as coisas de uma maneira que o usuário não precise saber como elas funcionam para usá-las e a maior parte da minha detecção de erros é feita em tempo de execução (o que não é apenas tarde demais, mas também aumenta o custo). Essencialmente, a única maneira de ser genérico em C é através dos dados, passo uma string de formato para printf ou scanf, que é avaliada em tempo de execução, por exemplo. É então difícil para o compilador provar que não estou usando algumas das opções que são teoricamente possíveis quando transmitidas aos dados corretos, o que significa geração potencial de código morto e perda de potencial de otimização.

Eu sei que posso estar desencadeando uma tempestade de merda aqui, mas minha experiência em microcontroladores de 32 bits é que, em uma comparação de maçãs com maçãs, C e C ++, ambos escritos por especialistas (como em C ++ potencialmente altamente modelado), o C ++ é a linguagem muito mais eficiente assim que possível. qualquer coisa precisa ser genérica (como em qualquer biblioteca) e é essencialmente equivalente em casos não genéricos. Também é mais fácil para um iniciante aproveitar o conhecimento de um implementador de biblioteca especializado em C ++.

Ao mesmo tempo, existem realmente poucas funções para as quais não posso passar dados incorretos, assim que a entrada não é um int, mas uma somethingpara a qual por acaso estou usando um int como método de representação, então existe um potencial para obtê-lo. errado (passe um valor inválido ou um 'otherThing' em vez de um 'algo'). Em C, meu único método de verificar se o usuário entendeu errado é em tempo de execução. No C ++, tenho a capacidade de executar algumas verificações, nem todas, mas algumas verificações em tempo de compilação, que são gratuitas.

No final do dia, uma equipe C é geralmente tão poderosa quanto seu programador mais fraco e o benefício do código resultante tem um multiplayer de 1 ou uma penalidade de desempenho. O que quero dizer com isso é que é alto desempenho para um e apenas um trabalho único em um ambiente único de decisões de design exclusivas ou é genérico o suficiente para ser usado em vários ambientes (outro microcontrolador, outra estratégia de gerenciamento de memória, outra latência vs. trade-offs etc., etc.), mas tem um custo de desempenho inerente.

Em C ++, as coisas podem ser encapsuladas por especialistas e usadas em muitos ambientes onde a geração de código de tempo de compilação se adapta à tarefa específica e a verificação estática impede que os usuários façam coisas estúpidas a custo zero. Aqui, temos muito menos trocas entre ser genérico e ser rápido e, portanto, do ponto de vista do custo versus benefício, são a linguagem mais eficiente, segura e produtiva.

É uma crítica válida que ainda haja uma grande escassez de boas bibliotecas C ++ para incorporação, isso pode levar a decisões pragmáticas de usar principalmente C em um compilador C ++. As decisões de usar apenas C em um projeto são essencialmente orientadas ideologicamente, por necessidade de suporte legado ou por uma admissão de que a equipe não é disciplinada o suficiente para evitar um conjunto muito seleto de coisas estúpidas que se pode fazer em C ++, mas não em C e ao mesmo tempo disciplinado o suficiente para não fazer nada do conjunto muito maior de coisas estúpidas contra as quais não se pode proteger em C, mas em C ++.


Boa adição à minha resposta :) Quem seria esse misterioso amante de C ++? Seu perfil afirma "Aparentemente, esse usuário prefere manter um ar de mistério sobre eles". (inglês ruim, BTW) MAS AHA a localização é "Bochum, Alemanha" ..... Vejo você na conferência!
Wouter van Ooijen

Ah sim atualizei meu perfil;) bom saber sua vinda para EMBO ++ será uma boa multidão
odinthenerd

10

Minha formação: acabei de sair da escola com os antigos programadores do Bell Labs; trabalha há 3 anos, 2 no projeto de pesquisa de graduação; aquisição de dados / controle de processo no VB.NET. Passou 1,5 anos trabalhando em um aplicativo de banco de dados corporativo no VB6. Atualmente trabalhando no projeto de PC embarcado com 2 GB de armazenamento, 512 MB de RAM, CPU x86 de 500 MHz; vários aplicativos executados simultaneamente em C ++ com um mecanismo IPC no meio. Sou jovem

Minha opinião: acho que o C ++ pode funcionar efetivamente, considerando o ambiente que escrevi acima . É certo que o desempenho difícil em tempo real não é um requisito para o aplicativo em que estou, e em alguns aplicativos incorporados, isso pode ser um problema. Mas aqui estão as coisas que aprendi:

  • C ++ é fundamentalmente diferente de C (ou seja, não há C / C ++). Enquanto tudo que é válido C é válido C ++, C ++ é uma linguagem muito diferente e é preciso aprender a programar em C ++, não em C, para usá-lo efetivamente em qualquer situação. No C ++, você precisa programar orientado a objetos, não processualmente e não um híbrido dos dois (grandes classes com muitas funções). Em geral, você deve se concentrar em criar turmas pequenas com poucas funções e compor todas as turmas pequenas em uma solução maior. Um dos meus colegas de trabalho me explicou que eu costumava programar proceduralmente em objetos, o que é uma grande bagunça e difícil de manter. Quando comecei a aplicar mais técnicas orientadas a objetos, descobri que a manutenção / legibilidade do meu código havia aumentado.

  • O C ++ fornece recursos adicionais na forma de desenvolvimento orientado a objetos que podem fornecer uma maneira de simplificar o código para facilitar a leitura / manutenção . Sinceramente, não acho que exista muita melhoria no desempenho / eficiência do espaço em fazer POO. Mas acho que a OOP é uma técnica que pode ajudar a dividir um problema complexo em vários pequenos pedaços. E isso é útil para as pessoas que trabalham no código, um elemento desse processo que não deve ser ignorado.

  • Muitos argumentos contra o C ++ estão relacionados principalmente à alocação dinâmica de memória. C também tem esse mesmo problema. É possível escrever um aplicativo orientado a objetos sem usar memória dinâmica, embora um dos benefícios do uso de objetos seja que você pode alocar essas coisas dinamicamente de maneira fácil. Assim como em C, você precisa ter cuidado com o gerenciamento de dados para reduzir vazamentos de memória, mas a técnica RAII simplifica isso em C ++ (faça com que a memória dinâmica seja destruída automaticamente, encapsulando-a em objetos). Em alguns aplicativos, onde cada local de memória conta, isso pode ser muito selvagem e confuso para gerenciar.

EDITAR:

  • Escreva a pergunta "Arduino C ++" : eu diria que o C ++ sem gerenciamento dinâmico de memória ainda pode ser útil. Você pode organizar seu código em objetos e, em seguida, colocá-los em vários locais do aplicativo, configurar interfaces de retorno de chamada, etc. Agora que desenvolvo em C ++, posso ver muitas maneiras pelas quais um aplicativo com todos os dados alocados no pilha ainda pode ser útil com objetos. No entanto, admito - nunca escrevi um aplicativo incorporado como esse para o Arduino, por isso não tenho provas por trás da minha reivindicação. Eu tenho algumas oportunidades para fazer algum desenvolvimento do Arduino em um próximo projeto - espero que eu possa testar minha reivindicação lá.

2
Gostaria de comentar o seu segundo ponto, você diz que ajuda a dividir um problema complexo em muitos pequenos pedaços e esse recurso deve ser ignorado. Esta é a razão exata pela qual sou tão pró-C ++. Um grande número de pesquisas sobre programação mostra que um crescimento linear no tamanho do programa fornece um crescimento exponencial no tempo de desenvolvimento. isso segue o caminho oposto, se você pode dividir adequadamente um programa, pode causar uma deterioração exponencial no tempo de desenvolvimento. Esta é de longe a coisa mais importante.
Kortuk

também no seu segundo ponto: o simples uso de uma metodologia de design de OOP não produz mais código compartimentado. Ter um bom design básico, como alguém expressa esse design é deixado para o desenvolvedor. OOP não define se você separa seu código corretamente, ele fornece outra opção e, além disso, a aparência que você fez, mas certamente não impõe um bom design, isso depende do desenvolvedor.
Mark

Isso é sempre verdade. Nunca ouvi falar de uma linguagem que imponha um bom design. Acho que principalmente sugerimos que esse é o trabalho dos desenvolvedores e que o C ++ facilita o uso e a implementação de maneira organizada.
Kortuk

@ Mark - eu concordo. Foi um processo de aprendizado para mim.
J. Polfer

7

Sim, o problema com o C ++ é o aumento da área de cobertura do código.

Em alguns sistemas, você está contando bytes e, nesse caso, terá que aceitar um custo de execução que, próximo aos limites de seus sistemas, aumentará o custo de desenvolvimento de C.

Mas, mesmo em C, para um sistema bem projetado, você precisa manter tudo encapsulado. Sistemas bem projetados são difíceis e o C ++ oferece aos programadores um lugar para um método de desenvolvimento muito estruturado e controlado. Há um custo para aprender POO e, se você quiser mudar, aceita muito; em muitos casos, a gerência prefere continuar com C e não pagar o custo, pois é difícil medir os resultados de um comutador que aumenta a produtividade. Você pode ver um artigo do guru de sistemas embarcados Jack Ganssle aqui .

Gerenciamento dinâmico de memória é o diabo. Na verdade, o diabo é de roteamento automático, o gerenciamento dinâmico de memória funciona muito bem em um PC, mas você pode esperar reiniciar um PC a cada poucas semanas, pelo menos. Você descobrirá que, como um sistema incorporado continua em funcionamento por 5 anos, o gerenciamento dinâmico de memória pode realmente ser estragado e realmente começar a falhar. Ganssle discute coisas como pilha e pilha em seu artigo.

Existem algumas coisas em C ++ que são mais propensas a causar problemas e usam muitos recursos, remover o gerenciamento de memória dinâmica e os modelos são grandes etapas para manter a pegada de C ++ mais próxima da pegada de C. Isso ainda é C ++, você não precisa de dinâmica gerenciamento de memória ou modelos para escrever um bom C ++. Não percebi que eles removeram exceções, considero as exceções uma parte importante do meu código que removo na versão, mas uso até esse momento. Nos testes de campo, posso fazer com que exceções gerem mensagens para me informar sobre uma exceção que está sendo capturada.


1
Eu costumava concordar que a pegada de código é um problema, mas recentemente parece que o tamanho do flash tem uma influência muito pequena no preço de um microcontrolador, muito muito menos que o tamanho da RAM ou o número de pinos de E / S.
Wouter van Ooijen

O argumento sobre memória dinâmica é IMO mais importante. Vi sistemas industriais que podiam funcionar por semanas sem parar, mas a camada de diagnóstico (escrita em C ++) limitaria o tempo para reiniciar em cerca de 12 horas.
Dmitry Grigoryev

6

Eu pensei que esse discurso anti-C ++ de Linus Torvalds era interessante.

Um dos piores recursos absolutos do C ++ é como ele torna muitas coisas tão dependentes do contexto - o que significa que, quando você olha para o código, uma exibição local raramente dá contexto suficiente para saber o que está acontecendo.

Ele não está falando sobre o mundo dos sistemas embarcados, mas sobre o desenvolvimento do kernel Linux. Para mim, a relevância vem disso: o C ++ requer a compreensão de um contexto maior e posso aprender a usar um conjunto de modelos de objetos, não confio em mim para lembrá-los quando precisar atualizar o código em alguns meses.

(Por outro lado, atualmente estou trabalhando em um dispositivo incorporado usando Python (não C ++, mas usando o mesmo paradigma OOP) que terá exatamente esse problema. Em minha defesa, é um sistema incorporado poderoso o suficiente para ser chamado de PC Há 10 anos.)


5
Podemos diferir, mas acho que, ao abrir qualquer projeto, não sei dizer o que está acontecendo imediatamente, mas se sei algo sobre o que está fazendo e tenho algo bem codificado em C e algo bem codificado em C ++, o C ++ sempre parece mais Claro. Você ainda precisa implementar o encapsulamento para um bom desenvolvimento em C, o que o C ++ facilita muito. O uso adequado de classes pode deixar bem claro onde estão as interfaces e elas podem ser completamente tratadas por meio de um objeto.
Kortuk

Totalmente acordado em encapsulamento e classes. Sobrecarga e herança do operador, nem tanto.
pingswept 15/06/10

1
Haha, sim, a sobrecarga do operador pode ser usada para ofuscar a função do código. Se alguém está sobrecarregando o operador, ele precisa ser por motivos claros ou não ter sido feito. A herança deve ser usada apenas em casos específicos em que você realmente está fazendo algo parecido com o pai com algumas adições. Eu acho que nem todos usariam qualquer função no OOP. Eu usei os dois, mas em um sistema incorporado não consigo pensar em um caso onde eu faria. Assim como eu acho que um compilador com um limite de 80 caracteres em nomes de variáveis ​​deve ser imediatamente descartado.
Kortuk

2
Eu apenas joguei acima em minha boca um pouco com a idéia de programar um MCU em Python ...
vicatcu

Você não é o único, mas se funcionar bem e for eficiente, eu posso perdoar.
Kortuk

6

Eu acho que outras respostas fizeram um bom argumento para os prós, contras e fatores de decisão, então gostaria de resumir e adicionar alguns comentários.

Para microcontroladores pequenos (8 bits), de jeito nenhum. Você está apenas pedindo para se machucar, não há ganho e você vai abrir mão de muitos recursos.

Para microcontroladores de última geração (por exemplo, 32 bits, 10s ou 100s de MB para RAM e armazenamento) que possuem um sistema operacional decente, é perfeitamente bom e, ouso dizer, até recomendado.

Então a pergunta é: onde está o limite?

Não sei ao certo, mas depois que desenvolvi um sistema para um uC de 16 bits com 1 MB de RAM e 1 MB de armazenamento em C ++, apenas para me arrepender mais tarde. Sim, funcionou, mas o trabalho extra que tive não valeu a pena. Eu tive que ajustá-lo, garantir que coisas como exceções não produzissem vazamentos (o suporte ao OS + RTL era bastante complicado e não confiável). Além disso, um aplicativo OO normalmente faz muitas alocações pequenas, e a sobrecarga de pilha para elas foi outro pesadelo.

Dada essa experiência, eu assumiria que, em projetos futuros, escolherei C ++ apenas em sistemas com pelo menos 16 bits e com pelo menos 16 MB para RAM e armazenamento. Esse é um limite arbitrário e provavelmente varia de acordo com coisas como o tipo de aplicativo, estilos de codificação e idiomas, etc. Mas, dadas as advertências, eu recomendaria uma abordagem semelhante.


2
Eu tenho que discordar aqui, não é um ponto repentino em que o C ++ se torna aceitável devido aos recursos do sistema, as boas práticas de design podem manter a pegada do C ++ onde a pegada do C é. Isso resulta em código com designs de OOP que ocupam o mesmo espaço. C mal escrito pode ser tão ruim quanto.
Kortuk

1
Bem, isso depende do tamanho do seu aplicativo e do quanto você usa determinados recursos que exigem mais espaço (como modelos e exceções). Mas, pessoalmente, prefiro usar C do que ter que me limitar a um C ++ restrito. Mas, mesmo assim, você terá a sobrecarga de uma RTL maior, thunks de método virtual, invocação de cadeia de construtor / destruidor ... esses efeitos podem ser mitigados com uma codificação cuidadosa, mas você estará perdendo o principal motivo do uso, abstração e perspectiva de alto nível.
Fceconel

4

Existem alguns recursos do C ++ que são úteis em sistemas incorporados. Existem outros, como exceções, que podem ser caros e cujos custos nem sempre são aparentes.

Se eu tivesse meus doutores, haveria uma linguagem popular que combinasse o melhor dos dois mundos e incluísse alguns recursos que faltam nos dois idiomas; alguns fornecedores incluem alguns desses recursos, mas não há padrões. Gostaria de ver algumas coisas:

  1. Exceção manipulando um pouco mais como Java, onde funções que podem lançar ou vazar exceções devem ser declaradas como tal. Embora um requisito para essas declarações possa ser um pouco chato do ponto de vista da programação, isso melhoraria a clareza do código nos casos em que uma função pode retornar um número inteiro arbitrário se for bem-sucedida, mas também pode falhar. Muitas plataformas poderiam lidar com isso de forma barata no código, por exemplo, tendo o valor de retorno em um registro e uma indicação de sucesso / falha no sinalizador de transporte.
  2. Sobrecarga de apenas funções estáticas e em linha; meu entendimento é que os órgãos de padrões para C evitaram sobrecarga de função, a fim de evitar a necessidade de nomes incorretos. Permitir sobrecargas de funções estáticas e embutidas evitaria esse problema e daria 99,9% do benefício de sobrecarregar funções externas (já que os arquivos .h poderiam definir sobrecargas embutidas em termos de funções externas com nomes diferentes)
  3. Sobrecargas para valores de parâmetros constantes arbitrários ou específicos resolvíveis em tempo de compilação. Algumas funções podem alinhar de maneira muito eficiente quando passadas com qualquer valor constante, mas alinhadas muito mal se passaram uma variável. Outras vezes, o código que pode ser uma otimização se um valor for constante pode ser uma pessimização, se não for. Por exemplo:
    copy_uint32s nulo inline (uint32_t * dest, const uint32_t * src, __is_const int n)
    {
      se (n <= 0) retornar;
      caso contrário, se (n == 1) {dest [0] = src [0];}
      caso contrário, se (n == 2) {dest [0] = src [0]; dest [1] = src [1];}
      caso contrário, se (n == 3) {dest [0] = src [0]; dest [1] = src [1]; dest [2] = src [2];}
      caso contrário, se (n == 4) {dest [0] = src [0]; dest [1] = src [1]; dest [2] = src [2]; dest [3] = src [3];}
      else memcpy ((void *) dest, (const void *) src, n * sizeof (* src));
    }
    
    Se 'n' puder ser avaliado em tempo de compilação, o código acima será mais eficiente do que uma chamada para memcpy, mas se 'n' não puder ser avaliado em tempo de compilação, o código gerado será muito maior e mais lento que o código que simplesmente chamado memcpy.

Eu sei que o pai do C ++ não gosta muito de uma versão incorporada do C ++, mas acho que poderia oferecer algumas melhorias consideráveis ​​em relação ao uso de C.

Alguém sabe se algo como o acima está sendo considerado para algum tipo de padrão?



@Joby Taffey: Eu acho que editei meu post para omitir que o criador do C ++ não estava interessado em um subconjunto incorporado; Estou ciente de que houve esforços, mas pelo meu entendimento eles realmente não chegaram tão longe. Eu acho que haveria uso definitivo para uma linguagem padronizada que seria acessível a processadores de 8 bits, e recursos como eu descrevi acima pareceriam úteis em qualquer plataforma. Você já ouviu falar de algum idioma que oferece coisas como o nº 3 acima? Parece muito útil, mas nunca vi nenhum idioma oferecer isso.
Supercat

"O pai do C ++" não tem experiência em programação de sistemas embarcados, então por que alguém se importaria com a sua opinião?
Lundin 4/15

@Lundin: O fato de algumas pessoas influentes parecerem se importar com suas opiniões sobre vários assuntos parece ser a razão, por si só, de outras pessoas fazerem isso. Estou pensando que, desde que escrevi o texto acima, o crescente poder dos modelos pode ter adicionado novas possibilidades de sobrecargas com base nas constantes que podem ser resolvidas em tempo de compilação, embora muito menos limpa do que se isso fosse suportado como compilação. recurso de tempo (pelo que eu entendi, seria possível especificar um modelo que deveria tentar várias coisas em ordem e seguir o primeiro que não falha ... #
686

... mas isso exigiria que o compilador desperdiçasse um pouco de esforço na compilação de substituições em potencial que acabariam sendo descartadas. Ser capaz de dizer com mais clareza "Se isso é uma constante, faça isso; caso contrário, faça isso" sem "partidas falsas" pareceria uma abordagem mais limpa.
precisa

3

C ++ é mais do que uma linguagem de programação:

a) É um "melhor" C b) É uma linguagem orientada a objetos c) É uma linguagem que nos permite escrever programas genéricos

Embora todos esses recursos possam ser usados ​​separadamente, os melhores resultados são alcançados quando os três são usados ​​ao mesmo tempo. No entanto, se você escolher apenas um deles, a qualidade do software incorporado aumentará.

a) É um C "melhor"

C ++ é uma linguagem tipificada forte; mais forte que C. Seus programas se beneficiarão desse recurso.

Algumas pessoas têm medo de indicadores. C ++ inclui as referências. Funções sobrecarregadas.

E vale a pena dizer: Nenhum desses recursos ocorreu em programas maiores ou mais lentos.

b) É uma linguagem orientada a objetos

Alguém disse neste post que abstrair a máquina em microcontroladores não é uma boa idéia. Errado! Todos nós, engenheiros embarcados, sempre abstraímos a máquina, apenas com outra sintaxe que a do C ++. O problema que vejo com esse argumento é que alguns programadores não estão acostumados a pensar em objetos, é assim que não vêem os benefícios do OOP.

Sempre que você estiver pronto para usar o periférico de um microcontrolador, é provável que o periférico tenha sido extraído para nós (de você ou de terceiros) na forma do driver do dispositivo. Como eu disse antes, esse driver usa a sintaxe C, como mostra o próximo exemplo (extraído diretamente de um exemplo NXP LPC1114):

/ * Configuração do temporizador para correspondência e interrupção em TICKRATE_HZ * /

Chip_TIMER_Reset (LPC_TIMER32_0);

Chip_TIMER_MatchEnableInt (LPC_TIMER32_0, 1);

Chip_TIMER_SetMatch (LPC_TIMER32_0, 1, (timerFreq / TICKRATE_HZ2));

Chip_TIMER_ResetOnMatchEnable (LPC_TIMER32_0, 1);

Chip_TIMER_Enable (LPC_TIMER32_0);

Você vê a abstração? Portanto, ao usar o C ++ para o mesmo objetivo, a abstração é levada para o próximo nível através do mecanismo de abstração e encapsulamento do C ++, a custo zero!

c) É uma linguagem que nos permite escrever programas genéricos

Os programas genéricos são alcançados por meio de modelos, e os modelos também não têm custos para nossos programas.

Além disso, o polimorfismo estático é alcançado com modelos.

Métodos virtuais, RTTI e exceções.

Há um comprometimento ao usar métodos virtuais: software melhor versus alguma penalidade no desempenho. No entanto, lembre-se de que a ligação dinâmica provavelmente será implementada usando uma tabela virtual (uma matriz de ponteiros de função). Eu fiz o mesmo em C várias vezes (mesmo regularmente), então não vejo as desvantagens em usar métodos virtuais. Além disso, os métodos virtuais em C ++ são mais elegantes.

Por fim, um conselho sobre RTTI e exceções: NÃO OS UTILIZE em sistemas embarcados. Evite-os a todo custo !!


2

Meu histórico, incorporado (mcu, pc, unix, outro), em tempo real. Segurança crítica. Eu introduzi um empregador anterior na STL. Eu não faço mais isso.

Algum conteúdo de chama

O C ++ é adequado para sistemas embarcados?

Meh. C ++ é uma dor para escrever e uma dor para manter. C + está bem (não use alguns recursos)

C ++ em microcontroladores? RTOSes? Torradeiras? PCs incorporados?

Mais uma vez eu digo Meh. C + não é tão ruim, mas o ADA é menos doloroso (e isso realmente está dizendo algo). Se você tiver sorte como eu, poderá fazer Java incorporado. O acesso verificado ao array e nenhuma aritmética de ponteiro criam códigos muito confiáveis. Os coletores de lixo no Java incorporado não são a prioridade mais alta, e há escopo de memória e reutilização de objetos; portanto, códigos bem projetados podem ser executados para sempre sem um GC.

OOP é útil em microcontroladores?

Claro que é. O UART é um objeto ..... O DMAC é um objeto ...

Máquinas de estado de objeto são muito fáceis.

O C ++ remove o programador muito longe do hardware para ser eficiente?

A menos que seja um PDP-11, C não é sua CPU. O C ++ era originalmente um pré-processador sobre o C, então Bjarne Stroustrup parava de rir por ter simulações lentas no Simula enquanto estava na AT&T. C ++ não é sua CPU.

Vá buscar um MCU que execute java bytecodes. Programa em Java. Rir dos caras do C.

O C ++ do Arduino (sem gerenciamento dinâmico de memória, modelos, exceções) deve ser considerado como "C ++ real"?

Não. assim como todos os bastardos compiladores C disponíveis para MCU's.

Em quarto lugar, o Java Incorporado ou o ADA Incorporado são padronizados (ish); tudo o mais é tristeza.


2
É fácil encontrar microcontroladores compatíveis com Java? Eu acho que isso limitaria as escolhas consideravelmente. E quais são suas experiências sobre penalidades de desempenho (já que nos EUA você normalmente não tem JIT)? E o impacto da imprevisibilidade do GC em sistemas em tempo real?
Fceconel

2
Quais MCUs existem por aí que suportam Java incorporado?
J. Polfer

www.ajile.com para iniciantes.
Tim Williscroft

+1 para Ada. Tem muita coisa a fazer no incorporado, incluindo o Arduinos.
Brian Drummond

A VM Java portátil para micros escrita em c é de código aberto. dmitry.co/index.php?p=./04.Thoughts/...
Tim Williscroft

-2

Os sistemas incorporados são projetados para executar alguma tarefa específica, em vez de ser um computador de uso geral para várias tarefas. Um sistema incorporado é uma combinação de hardware e software de computador. C é a mãe de todas as línguas modernas. É um nível baixo, mas oferece uma linguagem completa e lida com todo o tipo de hardware. Portanto, o C / C ++ é uma escolha ideal para o desenvolvimento de software para sistemas embarcados, que é bastante útil para todos os sistemas embarcados. Como sabemos, o C é uma linguagem em desenvolvimento. O UNIX do sistema operacional é escrito em C. Como o desenvolvimento bem-sucedido de software é tão frequentemente sobre a seleção do melhor idioma para um determinado projeto, é surpreendente descobrir que a linguagem C / C ++ se provou adequada para processadores de 8 e 64 bits. ; em sistemas com bytes, kilobytes e megabytes de memória. C tem o benefício da independência do processador, que permite que os programadores se concentrem em algoritmos e aplicativos, em vez de nos detalhes de uma arquitetura de processador específica. No entanto, muitas dessas vantagens se aplicam igualmente a outros idiomas de alto nível. Mas o C / C ++ teve êxito onde muitas outras linguagens falharam?


6
Eu realmente não tenho certeza do que isso adiciona à discussão.
Dave Tweed

-3

<rant>

Eu acho que C ++ é uma linguagem de baixa qualidade em primeiro lugar. Se você deseja usar o OOP, escreva programas Java. O C ++ não faz nada para impor paradigmas de POO, pois o acesso direto à memória está totalmente ao seu alcance para (ab) usar.

Se você possui um MCU, provavelmente está falando de menos de 100kB de memória flash. Você deseja programar em uma linguagem cuja abstração da memória seja: quando declaro uma variável ou uma matriz, ela obtém memória, ponto final; O malloc (também conhecido como palavra-chave "new" em C ++) deve ser mais ou menos proibido de usar em software incorporado, exceto talvez em raras ocasiões uma chamada durante a inicialização do programa.

Inferno, existem (frequentemente) momentos na programação incorporada em que C não é suficientemente baixo, e você precisa fazer coisas como alocar variáveis ​​para registradores e escrever montagem em linha para reforçar suas rotinas de serviço de interrupção (ISRs). Palavras-chave como "volátil" tornam-se muito importantes para entender. Você gasta muito tempo manipulando memória no nível de bits , não no nível de objeto .

Por que você quer se iludir pensando que as coisas são mais simples do que realmente são?

</rant>


Meu problema aqui é simplesmente: por que eu quero saber a complexidade do driver que foi escrito para controlar o USART1, se ele foi totalmente desenvolvido para lidar com a interface.
Kortuk

1
Eu não votei em negação de voto, mas gostaria de salientar que o C ++ não precisa impor OOP, apenas fornece as ferramentas para fazê-lo. Aplicar bons padrões de codificação é o trabalho do desenvolvedor. Pode ajudar se o idioma facilitar, mas o idioma nunca fará isso sozinho. C pode ser ilegível em alguns casos.
Kortuk

1
Todas as línguas são boas para alguma coisa. C ++ é rápido. OOP, se bem feito, torna muito mais fácil para vários desenvolvedores trabalharem em paralelo e codificarem para o desconhecido. Eu acho que é por isso que ele tem tanta tração no desenvolvimento de jogos.
perfil completo de Toby Jaffey

1
Sim eu concordo. A razão pela qual vejo isso no mundo incorporado é por causa da enorme quantidade de recursos e funções sendo adicionados a muitos dos diferentes sistemas já existentes e novos sistemas sendo desenvolvidos. Projeto ficar maior e maior. Ou levamos mais tempo para desenvolvê-los ou começamos a aplicar e contorcer o que o mundo da CS já fez nos PCs.
Kortuk

5
Outra pessoa que não entende C ++ corretamente. Sempre me surpreende quantas existem.
Rocketmagnet 22/02
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.