Preciso aprender C para entender como um computador funciona?

Eu sempre ouvi pessoas sugerindo estudar C. para entender o desempenho do computador.É uma boa idéia? Tem certeza Esbocarei imediatamente as conclusões do artigo, apenas para maior clareza:

  • C não é como o computador funciona.
  • Eu não acho que a maioria das pessoas fala literalmente, então isso não importa.
  • Compreender o contexto significa que aprender C por esse motivo ainda pode fazer sentido, dependendo de seus objetivos.

Pretendo escrever mais dois artigos com uma explicação mais detalhada das conclusões, mas isso já é suficiente. Adicione links aqui quando os artigos forem publicados.

Muitas vezes ouvi das pessoas isso:

Ao estudar C, você pode entender como os computadores funcionam.

Não acho que a ideia esteja inicialmente errada, mas tem algumas reservas. Se você os lembrar, pode muito bem ser uma estratégia viável para aprender coisas novas e importantes. No entanto, raramente vejo pessoas discutindo essas reservas em detalhes, por isso estou escrevendo este artigo para fornecer, em minha opinião, um contexto muito necessário ... Se você está pensando em aprender C a entender como o computador funciona, este artigo é para você. Espero que ela ajude você a descobrir.

Antes de realmente começarmos, gostaria de dizer mais uma coisa: se você quer aprender C, então estude! Aprender é ótimo. Aprender C se tornou muito importante para minha compreensão da computação e minha carreira. Aprender essa linguagem e seu lugar na história de uma linguagem de programação fará de você um programador melhor. Você não precisa de nenhuma desculpa. Aprenda as coisas apenas para aprender. Este artigo pretende ser uma diretriz para entender a verdade, não discute se deve ou não estudar C.

Antes de tudo, para quem essa idéia é geralmente recomendada. Se você está tentando "descobrir como os computadores funcionam", não é necessário dizer que atualmente você não entende isso. Quais programadores não entendem como os computadores funcionam? Eu basicamente vi que esse sentimento vem de pessoas que programam principalmente em linguagens de "script" de tipo dinâmico, como Ruby, Python ou JavaScript. Eles supostamente "não sabem como os computadores funcionam" porque essas linguagens funcionam dentro de uma máquina virtual, onde apenas a semântica da máquina virtual é importante. No final, toda a idéia de uma máquina virtual é fornecer portabilidade. O objetivo não é depender do equipamento em que a VM está sendo executada.

Há apenas um problema: C também funciona dentro de uma máquina virtual.

Máquina abstrata C


Na especificação C99 , seção 5.1.2.3, “Execução do Programa”:

As descrições semânticas nesta Norma descrevem o comportamento de uma máquina abstrata na qual os problemas de otimização não são relevantes.

Na minha opinião, é mais importante entender ao aprender C. A linguagem não "descreve como um computador funciona", mas descreve como uma "máquina C abstrata" funciona. Tudo o mais importante segue esse conceito.

Mais uma observação: aqui eu escolhi o C99, que não é o mais recente padrão C. Por que? Bem, a MSVC tem ... suporte interessante à linguagem C , e eu sou usuário do Windows atualmente. Sim, você pode executar o clang e o gcc no Windows. Não há uma diferença tão grande entre C89, C99 e C11 quanto ao que estamos falando. Em algum momento, você tem que escolher. A versão que mencionei aqui inclui algumas alterações na especificação original.

Você pode ter ouvido outra frase em sua palestra em C: "C é montador portátil". Se você pensar nessa frase, entenderá que, se isso for verdade, C não poderá corresponder à operação de um computador: existem muitos computadores diferentes com arquiteturas diferentes. Se C é como um montador que roda em computadores diferentes com arquiteturas diferentes, ele não pode funcionar simultaneamente exatamente como cada um desses computadores. Ele deve esconder os detalhes, caso contrário ele não será portátil!

No entanto, acho que esse fato não importa, porque as pessoas quase não estão literalmente se referindo a "C é como o computador funciona". Antes de retornar a isso, vamos falar sobre a máquina C abstrata e por que muitos parecem não entender esse aspecto de C.

Digressão: por que as pessoas estão enganadas?


Só posso falar da minha experiência, embora com certeza não seja única.

Aprendi GW-BASIC, C, C ++ e Java. Ouvi falar sobre Java antes de começar a escrevê-lo em 1999, quatro anos depois que ele apareceu. O marketing na época contrastou ativamente Java e C ++, concentrando-se na JVM como plataforma e no fato de que o modelo da máquina o distingue do C ++ e, portanto, a C. Sun Microsystems não existe mais, mas o espelho do comunicado de imprensa nos lembra:

Os aplicativos Java são independentes de plataforma; você só precisa portar a máquina virtual Java para cada plataforma. Ele atua como um intérprete entre o computador do usuário e o aplicativo Java. Um aplicativo gravado no ambiente Java pode funcionar em qualquer lugar, eliminando a necessidade de portar aplicativos para várias plataformas.

O lema principal era "Escreva uma vez, corra em todos os lugares". Essas duas frases tornaram-se como eu (e muitas outras) entendemos o Java e como ele difere do C ++. Java tem um intérprete, uma máquina virtual Java. Não há máquina virtual em C ++.

Com esse marketing poderoso, a “máquina virtual” na mente de muitas pessoas se tornou sinônimo de “um grande tempo de execução e / ou intérprete”. Os idiomas sem esse recurso estavam muito vinculados a um computador específico e exigiam portabilidade porque não eram verdadeiramente independentes de plataforma. O principal motivo pelo qual o Java existiu foi uma alteração nessa falha do C ++.

"Ambiente de tempo de execução", "máquina virtual" e "máquina abstrata" são palavras diferentes para o mesmo conceito fundamental. Mas desde então eles receberam conotações diferentes devido a uma ligeira variação na implementação dessas idéias.

Pessoalmente, acredito que esse marketing de 1995 seja a razão pela qual os programadores ainda não entendem a natureza de C.

Então, essa afirmação é falsa? Por que a Sun Microsystems gastaria milhões e milhões de dólares promovendo mentiras? Se C também é baseado em uma máquina abstrata que oferece portabilidade entre plataformas, por que precisamos do Java? Eu acho que essa é a chave para entender o que as pessoas realmente querem dizer quando dizem "C é como o computador funciona".

O que as pessoas realmente querem dizer?


Embora C funcione no contexto de uma máquina virtual, ainda é significativamente diferente das linguagens semelhantes a Java. Sun não mentiu. Para entender, você precisa conhecer a história de C.

Em 1969, o Bell Labs escreveu um sistema operacional de computador em linguagem assembly. Em 1970, foi apelidado de UNIX. Com o tempo, o Bell Labs comprou mais e mais novos computadores, incluindo o PDP-11.

Quando chegou a hora de portar o Unix para o PDP-11, eles decidiram usar uma linguagem de nível superior, o que era uma ideia bastante radical na época. Imagine que hoje vou lhe dizer: “Vou escrever um SO em Java” - você provavelmente rirá, embora a ideia seja realizável . A situação (no meu entender, eu não vivia na época) era aproximadamente a mesma. Consideramos uma linguagem chamada B, mas ela não suportava algumas das funções do PDP-11 e, portanto, elas criaram um sucessor chamando-a de "C", porque era a próxima letra do alfabeto.

Não havia idioma "A"; B conseguiu o BCPL (Basic Combined Programming Language).

Em 1972, o primeiro compilador C foi escrito no PDP-11 e, ao mesmo tempo, reescreveu o UNIX em C. Inicialmente, eles não pensavam em portabilidade, mas C ganhou fama, então os compiladores C foram portados para outros sistemas.

Em 1978, a primeira edição do livro "Linguagem de programação C" foi publicada. Chamado carinhosamente "K&R", de acordo com os nomes de seus autores, o livro não se parecia em nada com a especificação, mas ao mesmo tempo descreveu a linguagem em detalhes suficientes, como resultado dos quais outros também tentaram escrever compiladores C. Mais tarde, essa "versão" será chamada "K&R C".

À medida que o UNIX e o C se espalham, ambos foram portados para muitos computadores. Nos anos 70 e 80, sua base de hardware estava em constante crescimento. Da mesma maneira que C foi criado porque B não suportava todas as funções do PDP-11, muitos compiladores usavam extensões de idioma. Como havia apenas K&R e não uma especificação, isso foi considerado aceitável desde que as extensões estivessem razoavelmente próximas. Em 1983, a falta de padronização estava causando problemas, então a ANSI criou uma equipe para preparar a especificação. Em 1989, o padrão C89 foi lançado, às vezes chamado de "ANSI C".

A especificação C tentou unificar essas diversas implementações em vários hardwares. Portanto, a máquina C abstrata é um tipo da menor especificação possível que permitiria que o mesmo código funcionasse da mesma maneira em todas as plataformas. As implementações de C foram compiladas, não interpretadas, portanto não havia intérprete; portanto, não havia “VM” no sentido de 1995. No entanto, os programas C são gravados nesse computador abstrato inexistente e, em seguida, o código é convertido em assembler específico para o computador específico no qual o programa está sendo executado. Você não pode confiar em alguns detalhes específicos para escrever código portátil C. Isso torna muito difícil escrever portátil C, pois você pode ter assumido uma plataforma específica ao escrever a versão inicial do seu código.

Isso é melhor ilustrado por um exemplo. Um dos principais tipos de dados em C é char , da palavra "caractere". No entanto, a máquina C abstrata não determina quantos bits devem estar em char . Bem, determina, mas não pelo número; determina o tamanho de CHAR_BIT , que é uma constante. Seção 5.2.4.2.1 da especificação:

Os valores abaixo devem ser substituídos por expressões constantes que são adequadas ou usadas nas #if pré-processamento #if ... Os valores em implementações específicas devem ser iguais ou maiores em magnitude (valor absoluto) aos dados aqui com o mesmo sinal.

CHAR_BIT: 8

Em outras palavras, você sabe que char é pelo menos 8 bits, mas as implementações podem ser maiores. Para codificar corretamente uma “máquina C abstrata”, CHAR_BIT deve ser usado em vez de 8 como o tamanho no processamento de char . Mas isso não é algum tipo de função de intérprete, como pensamos em máquinas virtuais; esta é uma propriedade de como o compilador converte o código-fonte em código de máquina.

Sim, existem sistemas em que CHAR_BIT não CHAR_BIT 8 .

Portanto, essa "máquina abstrata", embora tecnicamente a mesma idéia que a máquina virtual Java, é mais provável uma construção de compilação para gerenciar compiladores para criar código assembler, em vez de algum tipo de verificação ou propriedade de tempo de execução. O tipo equivalente em Java é um byte , sempre com 8 bits, e a implementação da JVM é encarregada do que fazer em plataformas com mais bytes. (Não tenho certeza se a JVM funciona em qualquer uma dessas plataformas, mas é assim que deve funcionar.) A máquina C abstrata foi criada como um invólucro mínimo para vários "hardwares", e não como um tipo de plataforma feita de tecido sólido escrito em software para seu código.

Portanto, embora a Sun estivesse tecnicamente errada, na prática eles significam um pouco do que literalmente dizem, e o que eles querem dizer é verdade. A mesma coisa com a frase "Aprenda C para entender como os computadores funcionam".

Aprenda C para MELHOR Compreender como os computadores funcionam


O que as pessoas realmente querem dizer? No contexto de "um rubista deve aprender C para entender como os computadores funcionam" - este é um conselho para descer "ao nível do ferro". Ou seja, não apenas para entender como o seu próprio programa funciona dentro da máquina virtual, mas também como a combinação do programa e da VM funciona no contexto da própria máquina.

O Learning C fornecerá mais desses detalhes, porque a máquina abstrata está muito mais próxima do hardware, bem como das abstrações dos sistemas operacionais. A linguagem C é muito diferente das linguagens de alto nível, portanto, aprendê-lo pode ensinar muito.

Mas é importante lembrar que C é essencialmente uma abstração de hardware e as abstrações são imperfeitas. Cuidado com o que C faz ou como funciona com a própria máquina. Se você for muito fundo, certamente encontrará essas diferenças, que podem causar problemas. A maioria dos recursos de treinamento para C, especialmente hoje, quando o equipamento está se tornando mais homogêneo, promoverá a ideia de que é assim que um computador funciona. Portanto, pode ser difícil para um aluno entender o que está acontecendo sob o capô e qual é a abstração fornecida por C.

Nesta discussão, nem tocamos em outros assuntos. Por exemplo, devido à enorme popularidade de C, o hardware se tornou mais uniforme porque tende a avançar para a semântica da máquina abstrata C. Se sua arquitetura é muito diferente da semântica C, os programas C podem ser executados muito mais lentamente que outros. e a velocidade do hardware é frequentemente medida por testes em C. Este artigo já é bastante longo ...

Por esse motivo, acho que uma versão mais precisa dessa declaração seria "Ao aprender C, você aprenderá mais sobre como os computadores funcionam". Eu realmente acho que um conhecimento aproximado de C é útil para muitos programadores, mesmo que eles próprios não escrevam C. A introdução de C também dará uma idéia da história de nossa indústria.

Existem outras maneiras de explorar esse tópico; C não é inerentemente projetado para aprender sobre um computador, mas é uma boa opção.

Há muito o que aprender em programação. Desejo-lhe sucesso nesta jornada.

Source: https://habr.com/ru/post/pt426993/


All Articles