Por que os sistemas operacionais fazem coisas de baixo nível em C e C ++? Por que não apenas C ++?

20

Na página da Wikipedia para Windows , ele afirma que o Windows está escrito em Assembly para o carregador de inicialização e o alternador de tarefas, e C e C ++ para rotinas de kernel.

IIRC, você pode chamar funções C ++ a partir de um extern "C"bloco. Posso usar o C para as funções do kernel, para que aplicativos C puros possam usá-los (assim printfou não), mas se eles podem ser agrupados em um extern "C "bloco, então por que codificar em C?

Cole Johnson
fonte
10
Você já viu os vários "Por que usar C quando há C ++?" perguntas aqui? Isso não é necessariamente uma duplicata de nenhum deles, mas eles estão relacionados.
1
"você pode chamar funções C ++ a partir de um bloco externo" C "como C ++" Você quer dizer que pode chamar funções C ...?
Code-Guru
@ Code-Guru não, porque a única diferença entre funções exportadas C e C ++ é a decoração nome e em C ++, a adição da thisvariável
Cole Johnson
2
Lance uma exceção em um ISR e veja o que acontece #
James
Mais uma pergunta em C vs. C ++.
Machado

Respostas:

31

É principalmente por razões históricas. Algumas partes do kernel do Windows foram originalmente escritas em C, porque em 1983, há mais de três décadas, quando o Windows 1.0 foi lançado, o C ++ mal foi lançado. Agora, essas bibliotecas C permanecerão lá "para sempre", porque a Microsoft tornou a compatibilidade com versões anteriores um ponto de venda e a reescrita de uma versão compatível com erros das peças C em C ++ exige muito esforço, sem benefício efetivo.

back2dos
fonte
+1, acho que essa é a resposta mais realista (além do fato de que pode haver alguns desenvolvedores do kernel do Windows que simplesmente não gostam de C ++ ou não confiam nos compiladores C ++ para essas coisas de baixo nível). Veja, por exemplo, aqui stackoverflow.com/questions/520068/… , por que o kernel do Linux está escrito em C.
Doc Brown
@ back2dos - Embora o código C não seja jogado fora, isso não significa que será usado ou não atualizado. Eu garanto que você não é um método menos que faça algo que foi originalmente escrito e contido dentro de uma biblioteca C que tem sido portado uma biblioteca C ++ no Windows 8
Ramhound
8
É difícil acreditar que exista algum código do Windows 1.0 em qualquer versão recente do Windows. O Windows ME foi a última versão do Windows que não foi baseada na base de código do Windows NT. E mesmo isso foi amplamente substituído pelo novo kernel RT (que, pelo que entendi, não promete muito em termos de compatibilidade com versões anteriores).
TMN
@TMN: o argumento é provavelmente correta ou - Tenho a certeza na estrada de Win 1.0 agora não foram um monte de bibliotecas escritas em C que ainda fazem parte da base atual código Win8, e ninguém na MS vê qualquer benefício de reescrevê-los em C ++.
Doc Brown
1
Praticamente não existe nenhum código que fale com o kernel do Windows. Basicamente, apenas os motoristas fazem. Os aplicativos geralmente conversam com a API do Win32 ou possivelmente com a API do POSIX.
MSalters
24

Como a maioria das pessoas apontou, as razões são de longe históricas, mas há algo mais que ninguém está mencionando e acredito que é a razão pela qual as pessoas ainda escrevem código C para baixo nível.

C é uma linguagem pequena no sentido de que a especificação é (relativamente) curta. C ++ é enorme e isso é um eufemismo. Isso pode não importar muito para o programador (embora eu ache que sim), mas é extremamente importante se você deseja fazer a verificação formal . Além disso, existem ferramentas estabelecidas para análise de código C, que podem ajudar a evitar bugs, etc.

E isso é muito importante no software incorporado, onde o custo de um bug implantado é extremamente alto em relação ao restante do setor (compare a Web, onde você pode aplicar um patch imediatamente a todos os usuários). Sem mencionar software de missão crítica e material médico.

Houve tentativas de deslocar C de seu lugar dominante na programação de baixo nível com linguagens ainda melhores nisso, como o BitC, mas elas não tiveram sucesso até agora.

K.Steff
fonte
4
+1 Para mencionar software de missão crítica em C puro (por exemplo, software aeronáutico). No entanto, no software médico C ++ também é usado (testes extensivos são usados ​​em vez de uma verificação formal, o que seria extremamente difícil em C ++).
Giorgio
1
Além disso, C possui um subconjunto seguro bastante bem-sucedido MISRA-C. Existem equivalentes para C ++, mas eles ainda não são padrão de fato do setor. A tendência na programação crítica de segurança é que bibliotecas e compiladores também serão forçados a usar um subconjunto seguro como o MISRA. Reescrever uma versão compatível com MISRA-C ++ de toda a biblioteca padrão do C ++ provavelmente será um pesadelo.
2
As diretrizes do @Lundin MISRA não são um subconjunto seguro - você ainda possui indicadores brutos e a maioria dos outros recursos que tornam o C inseguro - eles se concentram principalmente em não usar ou documentar o comportamento específico da implementação.
Pete Kirkham
O @PeteKirkham MISRA-C captura todos os bugs de ponteiro mais clássicos e aplica a análise estática. Os padrões de segurança do setor (IEC 61508 et al) aparentemente aprovam o MISRA-C como um subconjunto seguro de C. Não há muitas outras alternativas úteis para software de missão crítica, a menos que você escolha o SPARK Ada, um idioma que poucos conhecem, com ferramentas limitadas Apoio, suporte.
2
Isso deveria ter sido selecionado como a melhor resposta, pois está correto. Outros que sugerem que C é usado apenas por razões históricas são histéricos em si.
Rob
15
  1. O tempo de execução C é muito menor.
  2. A tradução de C ++ em construções de nível inferior é menos transparente que em C. (Veja referências e vtables, para dois exemplos rápidos)
  3. C geralmente tem um ITB estável. C ++ geralmente não. Isso significa que, no mínimo, a interface de chamada do sistema deve ser do estilo C. Além disso, se você quiser algum tipo de módulo dinâmico, ter uma ABI consistente ajuda muito.
wnoise
fonte
+1 para (2) e (3). Não estou convencido de (1).
Thomas Eding
7
@ Thomas Thing: O tempo de execução C ++ consiste no tempo de execução C, além de recursos do C ++, como exceções, RTTI e outro alocador de memória. YMMV para saber se isso conta muito maior. (E depois há a biblioteca padrão ...)
wnoise
Ah, esqueci as exceções e os novos / excluímos pools. RTTI eu nunca uso: D
Thomas Eding
11

Os motivos não são técnicos. Um pouco de montagem é inevitável, mas eles não são forçados a usar o C ocasional, eles querem . Minha empresa usa seu próprio kernel proprietário, escrito quase inteiramente em C ++, mas não precisamos suportar uma interface C para o kernel como quase todos os outros, porque nosso kernel incorporado é compilado monoliticamente com nossos aplicativos C ++. Quando você tem uma interface C, geralmente é mais fácil escrever o código da interface em C, mesmo que seja possível usá extern "C"-lo em C ++.

Até temos um número considerável de arquivos C, principalmente devido ao código de terceiros. O código de baixo nível de terceiros é quase sempre fornecido em C, porque é muito mais fácil incorporar o código C em um aplicativo C ++ do que o contrário.

Karl Bielefeldt
fonte
6

Os desenvolvedores de kernel geralmente são o tipo de pessoa que se sente mais feliz, quando é imediatamente evidente a partir da fonte, o que o código realmente faz.

O C ++ possui muito mais recursos, que escondem o que o código faz mais do que o simples código C o oculta: sobrecargas, métodos virtuais, modelos, referências, lançamentos ... O C ++ também possui muito mais sintaxe que você precisa dominar para entender o C ++ código usando-o.

Eu acho que o poder do C ++ é uma ferramenta muito poderosa para criar bibliotecas e estruturas, o que torna o desenvolvimento de aplicativos fácil. Muitas vezes, o desenvolvedor de aplicativos C ++ ficava totalmente perdido nas entranhas cheias de modelos de uma biblioteca, mesmo quando ele é muito competente na criação de aplicativos usando essa biblioteca. E escrever corretamente uma biblioteca C ++ é uma tarefa de programação muito desafiadora e realizada apenas para fornecer uma ótima estrutura para o benefício do desenvolvedor de aplicativos. As bibliotecas C ++ não são internamente simples, são (ou podem ser ...) apenas poderosas, mas simples do ponto de vista dos programadores de aplicativos.

Porém, a API do kernel não pode ser uma API C ++, deve ser uma API independente da linguagem; portanto, a maioria das coisas boas do C ++ não seria diretamente utilizável nessa interface. Além disso, o kernel não é realmente dividido em partes de "biblioteca" e "aplicativo" desenvolvidas de forma independente, com mais esforço logicamente em uma biblioteca, para facilitar a criação de uma massa de aplicativos.

Além disso, a segurança e a estabilidade são mais críticas dentro de um kernel, e os métodos virtuais são muito mais dinâmicos e, portanto, muito mais difíceis de isolar e verificar do que os retornos de chamada simples ou outros mecanismos do tipo C.

Resumindo, embora você possa, naturalmente, escrever qualquer programa em C, incluindo um kernel como C ++, a maior parte do poder do C ++ não é bem usado no kernel. E muitos argumentam que as ferramentas de programação devem impedir que você faça coisas que não deve fazer. C ++ não faria.

hyde
fonte
+1. Como desenvolvedor de kernel, minha "regra de ouro" é que, se você não pode estimar facilmente as "linhas de cache tocadas", o idioma que você está usando está fazendo mais mal do que bem.
Brendan
Esclarecimento: Para os kernels, você deve assumir que a CPU gasta a maior parte do tempo no espaço do usuário e o código do kernel é usado esporadicamente (por exemplo, quando o espaço do usuário chama a API do kernel ou ocorre uma interrupção); o que significa que você deve assumir "cache frio". Para CPUs modernas (onde a RAM é lenta em relação à velocidade da CPU), os erros de cache e TLB são caros; portanto, (combinada com a expectativa de "cache frio"), a métrica "linhas de cache tocadas" se torna um indicador extremamente importante para desempenho e / ou escalabilidade.
Brendan
5

Bjarne Stroustrup, em entrevista em julho de 1999 :

Nenhuma dessas línguas era radicalmente diferente ou dramaticamente melhor que outras línguas contemporâneas. Eles eram, no entanto, bons o suficiente e os beneficiários de sorte e fatores sociais

david
fonte
2
Bem-vindo David. Ao citar ou citando, é uma boa idéia para fornecer uma referência (adicionado!)
Andrew
3

C é uma linguagem de nível muito baixo, por seu design. Está a um passo do montador; conhecendo o chipset que você está alvejando, você poderia, com um pouco de conhecimento, "compilar" manualmente o C no ASM. Esse tipo de linguagem "próxima ao metal" é essencial para altos níveis de otimização (desempenho, eficiência de memória etc.). No entanto, por ser tão próximo do metal, você não ganha muito de graça com esse idioma; é uma linguagem processual, não orientada a objetos, e, portanto, trabalhar com essas construções envolve muito código padrão para criar e consumir construções com vários valores na memória.

C ++ é "C one better", adicionando uma série de recursos fáceis de usar, como alocação dinâmica de memória, organização interna da estrutura, uma grande biblioteca de códigos predefinidos, etc., à custa de algumas perdas de eficiência (ainda muito melhores ambientes de tempo de execução gerenciado). Para o codificador médio, as vantagens superam as desvantagens em áreas da base de código que não precisam de controle retentivo anal da alocação de memória, etc.

A combinação dos dois é bem tradicional; você usa C para escrever as áreas mais críticas em termos de desempenho e com eficiência de memória da base de código, com as quais você pode trabalhar de uma maneira mais abstrata por meio de chamadas de método do código C ++, que podem ser mais elegantemente organizadas e projetadas do que o desempenho superior , código C super otimizado.

KeithS
fonte
2
Em relação à eficiência, vou me repetir: (1) O pessoal do C ++ dirá que isso é besteira. (2) Estou dizendo que não vejo razão para que isso aconteça e gostaria de exemplos concretos. Não são exemplos de como é fácil escrever código menos eficiente, mas exemplos de como ser tão eficiente quanto C exigem feiúra indevida.
3
Defina "feio"; Eu codifico em C # para ganhar a vida e, sempre que vejo exemplos de código C ++ no StackOverflow, fico impressionado com a quantidade de cruft considerada normal no uso diário da linguagem. Quando eu codifiquei em C ++, quando, muitas vezes, vi o código C e encolheu; tipos de estrutura de embalagem manual, cálculos de ponteiro de execução para saltos manuais, ASM incorporado ... eca. Algumas pessoas lamentam a perda de conhecimento de baixo nível entre os programadores Java / .NET; Considero um enorme benefício para a produtividade.
Keiths
1
Você não respondeu minha pergunta;) Por "feio" quero dizer "feio pelos padrões dos gurus em C ++". Em outras palavras, exemplos em que não se pode usar "C ++ moderno" e ser tão eficiente quanto C.
2
Isso pode ser verdade (sinceramente não sei). Para o desenvolvimento do kernel (e alguns outros campos), não estamos falando de programadores comuns.
3
As pessoas esquecem que C -> C ++ é um continuum. Freqüentemente, esses argumentos estão comparando C ++ moderno e bom com C. Você pode pegar um programa C e compilá-lo com um compilador C ++ em um tempo relativamente curto, e ele será executado com a mesma rapidez. Se um recurso moderno do C ++ for "muito lento", não o use. Isso pode até incluir coisas como iostream. "Lento demais" nunca é uma boa desculpa para usar C sobre C ++.
Gort the Robot
1

Pode ser que, com C, você gaste a maior parte do tempo pensando no problema em questão e em como codificar a solução. Em C ++, você acaba pensando em C ++ e sua infinidade de recursos, funções e sintaxe obscura.

Também em muitas lojas C ++, seu código é monitorado pela "polícia da moda", fascinada pelo último conjunto de padrões de design ou pelos últimos pronunciamentos ininteligíveis do grande deus Stroustrup. O código bonito se torna mais valorizado do que o código em funcionamento, admirar o uso do conjunto mais recente de modelos Boost é mais do que encontrar uma solução funcional para os negócios.

Minha experiência é que, para todos os recursos inteligentes e a pureza OO do C ++, a codificação em C simples faz o trabalho com mais rapidez e eficácia.

James Anderson
fonte
0

É possível que as partes C não sejam portáveis ​​para o compilador C ++ usado para as partes C ++. Talvez o código C seja amigável com o compilador C de maneiras que rompem com o compilador C ++.

Se você possui um compilador C ++ de qualidade, quase não há razão para misturar C e C ++ em um projeto. Quase.

A única razão seria que o seu projeto compartilha o código C com outros projetos, o código não é compilado como C ++ e você não deseja manter uma bifurcação em C ++ desse código.

Kaz
fonte
-1

Eu acho que você tem o contrário - o extern "C"bloco garante que as convenções de chamada C sejam usadas para todas as funções dentro do bloco. Portanto, você pode chamar funções C puras do C ++, e não as funções C ++ do C. Independentemente, imagino que a razão pela qual as pessoas usem C e C ++ seja porque muitas bibliotecas de baixo nível são escritas usando C, e é mais fácil usar algo que já existe (e é presumivelmente depurado e otimizado) do que escrever o seu próprio. OTOH, C ++ oferece muitos recursos agradáveis ​​de alto nível com os quais as pessoas preferem trabalhar, então usam isso para o resto.

TMN
fonte
-2

Existem vários níveis de plataformas incorporadas usando C como linguagem de programação (é claro que é sua liberdade usar a linguagem assembly a qualquer momento)

Para 'Level', estou falando do nível de recurso SRAM e ROM interno de um sistema.

Essas plataformas às vezes têm recursos limitados (por exemplo, algumas plataformas 8051 possuem apenas 128 bytes de SRAM do usuário).

Não faz sentido oferecer suporte à alocação dinâmica de memória com uma quantidade tão pequena de RAM. (novo / excluir) ou até malloc em C.

Uma das principais melhorias de C para C ++ é o paradigma orientado a objetos. C ++ é adequado em software com maior espaço de memória

mas não no firmware incorporado com limitação de tamanho de até 32 KB. (por exemplo, em uma placa MCU de 16 bits)

Não há necessidade de ter um compilador C ++ que geralmente é mais complicado que o compilador C. (pelo menos os provedores de SDK não se incomodam em fazer isso).

Na verdade, mal consigo encontrar um compilador C ++ em uma plataforma ARM7 de 32 bits.

Simplesmente não vale a complexidade

Em alguns 8051 (8 bits): 1MB ROM, 128B RAM

TI MSP430 (16 bits): ROM de 32 KB, RAM de 4KB

Núcleo da CPU ST Microelectronics ARM Cortex ™ -M3 de 32 bits (STM32F103T4): 16 ou 32 Kbytes de memória Flash 6 ou 10 Kbytes de SRAM

ansonchau
fonte
2
Isso não é novidade para as outras respostas já postadas aqui.
Martijn Pieters
Um compilador C ++ de 32 bits para ARM? Se você quiser, poderá compilar o LLVM a partir da fonte depois de algumas modificações para obter um compilador C ++ para iOS.
Cole Johnson
-4

Vejo algumas razões possíveis:

  • C é um pouco mais eficiente se comparado ao equivalente em C ++.
  • Algumas bibliotecas usadas são escritas em C.
  • Eles usam algumas partes do kernel do Linux, escritas em C.

Editado: Como se vê, o terceiro argumento não é verdadeiro (ver comentários).

Pijusn
fonte
5
(1) O pessoal do C ++ imploraria para diferir. E, objetivamente, não vejo razão para que isso aconteça. (2) O C ++ pode chamar o código C muito bem (esse é o ponto inteiro da compatibilidade com versões anteriores e extern "C").
1
Se a MS usa algumas partes do kernel Linux, e o kernel Linux é GPL, isso não significa que o Windows também precisaria ser GPL?
TomJ
1
@ TomJ, na verdade, é por isso que eles foram forçados a doar alguns milhares de linhas para o Linux também. + Por que você acha que eles suportam o desenvolvimento do Linux?
Pijusn
2
@Pius O argumento dele é (e ele está certo no AFAIK), se houvesse o código da GPL vinculado ao kernel do Windows, todo o kernel teria que ser GPL (desde que não haja um contrato separado com os detentores dos direitos autorais).
@ Delnan, não tenho certeza sobre os detalhes. Eu não sou advogado, então não posso comentar sobre isso. Mas houve um pequeno escândalo há alguns anos atrás sobre isso. Não tenho certeza, mas acho que poderia ter sido o módulo de rede que tratava de toda a loucura.
Pijusn
-4

Porque C é sem dúvida uma linguagem melhor que C ++. E porque parte do código foi escrito antes do C ++ se tornar popular e as pessoas não tiveram um motivo para substituí-lo.

E como o C ++ possui muitos recursos que podem quebrar seu código, se você não tomar cuidado ao usá-lo em um kernel.

Minthos
fonte
C ++ espera bibliotecas dinâmicas? E o que é memória dinâmica?
4
-1 para [stuff] that C++ expects. Por que o C ++ usa mais heap que o C? Por que o C ++ requer mais dlls que o C? Simplesmente NÃO É VERDADEIRO
Thomas Eding
1
Correção: você perde as bibliotecas que são escritas em C ++. Então, volte ao quadrado 1 se você estiver usando C ++ ou C. Por que se limitar à funcionalidade C, se você pode usar modelos, classes, destruidores, const e todos os tipos de outras coisas.
Thomas Eding
6
O que? Modelos, exceções, objetos (incluindo construtores, destruidores, operadores sobrecarregados, agora movem a construção e - praticamente? - tudo o resto) etc. funcionam muito bem, independentemente da origem da memória (pilha, memória estática, seu pool personalizado ou qualquer outra coisa) . Os contêineres padrão usam a alocação de heap por padrão, mas seus alocadores podem ser personalizados e os caras do kernel gravam suas próprias coleções e gerenciamento de memória de qualquer maneira. -1
2
FYI: Tirei meu voto negativo porque não acho que sua resposta seja ativamente prejudicial agora, mas também não a considero particularmente útil ou perspicaz.