É necessário entender o que está acontecendo no nível do hardware para ser um bom programador?

24

Sou um programador autodidata, caso essa pergunta seja respondida no CS 101. Aprendi e usei muitas línguas, principalmente para meu uso pessoal, mas ocasionalmente para coisas profissionais.

Parece que estou sempre correndo contra a mesma parede quando me deparo com problemas na programação. Por exemplo, acabei de fazer uma pergunta em outro fórum sobre como lidar com um ponteiro para matriz que foi retornado por uma função. Inicialmente, estou pensando que simplesmente não conheço a técnica adequada que os designers de C ++ configuraram para lidar com a situação. Mas, pelas respostas e discussões que se seguem, vejo que realmente não entendo o que acontece quando algo é 'devolvido'.

Quão profundo é o nível de entendimento do processo de programação que um bom programador deve alcançar?

bev
fonte
3
Meu conselho: Aprenda algumas montagens x86 (DOS ou outras). Em seguida, aprenda a ler parte da saída do assembler de alguns pequenos pedaços de código C. Faça perguntas se você não entender a saída. Repetir. Isto irá forçá-lo a entender o que está acontecendo no nível CPU
Earlz
Earlz - Você quer dizer que eu deveria aprender a programar usando o conjunto de instruções x86? Esse é o 'nível de CPU'?
Bev
Job - thx, isso foi divertido. Ele realmente cometeu alguns erros, embora apenas para sua informação.
22411 bev

Respostas:

33

Não. Ninguém entende o que está acontecendo no nível do hardware.

Os sistemas de computador são como cebolas - há muitas camadas, e cada uma depende da camada abaixo dela para suporte. Se você é o cara que trabalha em uma das camadas externas, não deve se importar muito com o que acontece no meio da cebola. E isso é bom, porque o meio da cebola está sempre mudando. Contanto que a camada ou camadas que suportam sua camada específica continuem com a mesma aparência e suportem sua camada, você estará bem.

Mas, novamente ...

Sim. Quero dizer, você não precisa entender o que realmente está acontecendo dentro da cebola, mas ajuda muito ter um modelo mental de como é o interior de uma cebola típica. Talvez não seja a parte mais profunda, onde você tem portas compostas por transistores e coisas assim, ou a próxima camada ou duas, onde você tem microcódigo, relógio, unidades de decodificação de instruções etc. As próximas camadas, no entanto, são onde você tenho registros, a pilha e a pilha. Essas são as camadas mais profundas em que você tem muita influência sobre o que acontece - o compilador traduz seu código em instruções executadas nesse nível e, se você quiser, geralmente pode percorrer essas instruções e descobrir o que "realmente" está acontecendo.

A maioria dos programadores experientes tem uma versão ligeiramente de conto de fadas dessas camadas na cabeça. Eles ajudam a entender o que o compilador está falando quando informa que houve uma "exceção de endereço inválido" ou um "erro de estouro de pilha" ou algo assim.

Se você estiver interessado, leia um livro sobre arquitetura de computadores. Nem precisa ser um livro particularmente novo - os computadores digitais estão trabalhando aproximadamente da mesma maneira há muito tempo. Quanto mais você aprender sobre o interior da cebola, mais espantado ficará que alguma dessas coisas funcione! Aprender (aproximadamente) o que está acontecendo nas camadas inferiores torna a programação menos misteriosa e, de alguma forma, mais mágica. E realmente, mais divertido.

Outra coisa que você pode ver são as cebolas embutidas. Quero dizer, sistemas embarcados. Há várias plataformas incorporadas que são bastante fáceis de usar: Arduino e BASIC Stamp são dois exemplos. Estes são basicamente pequenos microprocessadores com muitos recursos internos. Você pode pensar nelas como cebolas com menos camadas do que o seu PC de mesa típico, portanto, é possível obter uma compreensão bastante completa do que está acontecendo em todo o sistema, do hardware ao software.

Caleb
fonte
2
Obrigado. Isso basicamente responde à minha pergunta. Eu sou um EE que fez o design no nível de chip (ou seja, no transistor) de registradores, somadores, multiplexadores, etc., por isso obtenho o nível mais baixo (a menos que falemos de mecânica quântica). Também posso usar os idiomas que conheço bastante bem. Eu só tenho uma enorme lacuna no nível intermediário (pilha, pilha), onde você diz que o compilador faz seu trabalho. Como você diz, quero que minha experiência em programação seja "menos misteriosa e, ..., mais mágica". parece que eu deveria estudar os níveis que ainda são desconhecidos para mim.
Bev
@ bev: Nesse caso, você realmente deve verificar uma plataforma como o Arduino.
Caleb
desculpe-me por ser chato, mas fiz o check-out do Arduino e não consigo ver como usá-lo me ajudaria a entender como um compilador trata ponteiros e matrizes de maneira diferente. O que não estou vendo?
22411
@ev: Se você quiser apenas descobrir como as funções são chamadas, provavelmente você pode gastar 30 minutos lendo sobre isso e pronto. Se você quiser ter uma noção melhor de como tudo funciona juntos, será mais fácil com um sistema pequeno. É a melhor maneira de colocar toda a cebola na cabeça de uma só vez. O AVR, a família de chips em que o Arduino se baseia, é um sistema agradável, de uso geral e fácil de usar, com um conjunto de instruções pequeno o suficiente para aprender sem muita dificuldade.
Caleb #
Ah ok. A página inicial é um pouco obscura sobre esse aspecto de seus produtos. Eu vou olhar de novo.
22411
10

Você não está falando sobre o nível de hardware, mas sobre o que o compilador realmente faz com o que você diz para fazer.

Você certamente precisa desse nível de entendimento para descobrir o que deu errado quando não é óbvio, especialmente ao lidar com uma situação de perda de memória.

Loren Pechtel
fonte
Loren - Sim! Obrigado pela verdade simples. Agora preciso descobrir a melhor maneira de aprender o que os compiladores c ++ fazem com seus tipos de dados. BTW, como EE, eu sei que não é o nível de hardware literalmente. Eu simplesmente não sabia como vocês chamam de CS. (Ainda não para que o assunto nível Compiler.?)
Bev
BTW - memória stomp?
22411 bev
@ Bev: Você acabou de provar o meu ponto aqui - se você nem sabe o que é um stomp de memória, terá um tempo terrível para encontrar um bug devido a um. Um stomp de memória é quando algo grava em um local que não deveria e apaga (stomps) o que aconteceu estar lá. Se você tiver sorte, o que quer que acerte é imediatamente vital e, pelo menos, explode. Se você não tiver sorte, o programa continua com alguns buracos nos dados.
Loren Pechtel 18/10/11
obrigado pelo esclarecimento. Isso também me mostra o quanto eu não sei, já que, tanto quanto eu sei, acabei de escrever na pilha ou na pilha, sem um controle mais preciso.
22411
@ Bev: O problema surge quando você escreve em algum lugar que não pensa que está escrevendo. Você tem algo na pilha e faz um ponteiro para ela. Você sai da rotina - o item desaparece, o ponteiro não. Agora, o que acontece quando você escreve para esse ponteiro? Ou você tem uma variedade de 100 itens - o que acontece quando você escreve no item 200?
Loren Pechtel 18/10/11
6

Noções básicas sobre memória de programa! = Noções básicas sobre hardware

Compreendendo a hierarquia de memória == Compreendendo o hardware


Para responder sua pergunta genérica: Depende. Não é demais entender o hardware, mas entendê-lo não ajudará em todos os casos.

Com base no seu exemplo, você só precisa entender mais sobre como a memória é dividida e como é organizada quando você está executando um programa. A compreensão do hardware não o ajudará nesse sentido, porque a memória (como visível para um programa) nem mesmo representa o hardware de verdade, graças à magia da memória virtual.

Se você estava curioso sobre problemas de desempenho com base na ordem em que acessa a memória, AGORA você se beneficiaria com a compreensão do hardware, a hierarquia de memória, falhas de cache, falhas de página e toda a gloriosa bondade maravilhosa que vem do hardware.

riwalk
fonte
Stargazer - Ainda não estou no ponto em que posso me preocupar com problemas de desempenho. Em breve, espero. Obrigado por seus comentários.
22411 bev
5

Se você não decidir a aprender um pouco de assembler, você provavelmente deve aprender algo como 6502 assembler em um Commodore 64 (emulado, é claro), ou 68000 em um Amiga.

Você pode ter uma idéia do Commodore 64 aqui ...

http://thepiratebay.org/torrent/4609238/Tag3-Saal2-Slot16_00--ID2874-the_ultimate_commodore_64_talk-Main

O clássico livro "tudo o que você precisa saber" é o descrito aqui ...

http://reprog.wordpress.com/2010/03/12/programming-books-part-3-programming-the-commodore-64/

Provavelmente, você pode encontrar uma digitalização em PDF se olhar em volta.

O IMO, 6502 é mais fácil que o Z80 e 68000 é mais fácil que o 8086 - conjuntos de instruções mais regulares etc.

Mas a CPU é apenas um aspecto do hardware. Além disso, uma CPU moderna é uma fera massivamente diferente e faz coisas transparentes mesmo do ponto de vista dos compiladores - como apresentar um espaço de endereço virtual.

Uma vantagem particular do 6502 no C64 é que não apenas a CPU é simples, mas também há algumas muito simples de se mexer com o hardware. Eu me divertia muito brincando com o chip de música SID.

Então - provavelmente é um exercício que vale a pena se você não gastar muito tempo com ele. Eu aprendi o 6502 assembler como minha segunda língua quando eu tinha 14 anos, logo após o Commodore Basic. Mas, na maioria das vezes, ele está obtendo esse modelo de trabalho muito simples, para que você possa adicionar idéias mais sofisticadas com um mínimo de mal-entendido.

Algumas coisas úteis que você pode aprender trabalhando em assembler ...

  • Como os registros da CPU funcionam.
  • Como o endereçamento de memória funciona, incluindo a indireção.
  • Como a pilha da CPU funciona.
  • Como a lógica bit a bit funciona.
  • Como a CPU controla os dispositivos de E / S.
  • Como as interrupções funcionam.

Uma razão particular pela qual eu recomendo é obter uma melhor intuição da maneira como as etapas simples operam inteiramente determinística e mecanicamente e totalmente sem inteligência ou bom senso. Basicamente, acostumar-se ao modelo de execução imperativa em sua forma mais pura e teimosamente ignorante.

Precisamente quão útil é conhecer a maioria dessas coisas agora, no entanto, é uma pergunta difícil.

Uma coisa que você não aprenderá é como jogar bem com uma hierarquia de memória. Essas máquinas antigas geralmente tinham um modelo de memória simples, sem camadas de cache e sem memória virtual. Você também não aprenderá muito sobre concorrência - eles certamente eram maneiras de lidar com isso, mas na maioria das vezes significava interrupções. Você não precisava se preocupar com mutexes etc.

Às vezes, um modelo mental de como essas coisas uma vez trabalhou, ou de como funciona a montadora, pode até enganar. Por exemplo, pensar em um ponteiro C como um endereço pode levar a problemas de comportamento indefinidos. Normalmente, o ponteiro AC é implementado como um número inteiro contendo um endereço, mas não há garantia de que isso seja verdade. Por exemplo, em algumas plataformas bizarras, ponteiros diferentes podem apontar para diferentes espaços de endereço. Isso se torna importante quando você deseja fazer aritmética ou lógica bit a bit com dois ponteiros.

A menos que você tenha uma dessas plataformas bizarras, talvez não pense que se importa com isso - mas os compiladores hoje em dia têm cada vez mais probabilidade de explorar o comportamento indefinido dos padrões para otimização.

Portanto, um modelo mental da arquitetura do sistema pode ser útil, mas ainda é importante codificar para as especificações da linguagem, não para um modelo hipotético que sua linguagem e plataforma possam não respeitar.

Finalmente, muitas coisas úteis de modelos mentais vêm da idéia de como os compiladores geram código - e a geração de código para linguagens modernas é muito diferente dos compiladores bastante triviais disponíveis na época.

Este é o meu livro favorito por isso ...

http://dickgrune.com/Books/MCD_1st_Edition/

Juntamente com o material sobre análise e ASTs, etc, abrange a geração de código para uma variedade de paradigmas de linguagem - imperativos, OOP, funcionais, lógicos, paralelos e distribuídos - e também para gerenciamento de memória. Se você quiser saber como as chamadas de método polimórfico funcionam sem se atolar nos detalhes do conjunto de instruções da CPU, um livro como este é seu amigo - e haverá uma nova edição em breve.

Steve314
fonte
Steve - uau. Estou quase sem palavras com a abrangência e o foco da sua resposta à minha pergunta. Muito obrigado por reservar um tempo para escrever essa coisa toda. Definitivamente vou aceitar suas sugestões.
22411
11
Eu sugeriria que o montador PDP-11 seja um pouco mais agradável de aprender do que todos os outros mencionados. O que todos os outros ensinam são as limitações impostas por recursos de hardware mais limitados e / ou por um design e previsão de hardware mais limitados. Algo como uma família muito comum do 8051 ensina o quão bizarro o modelo de programação pode obter em um hardware tão limitado (onde a menção de Steve de diferentes espaços de endereço, por exemplo, entra em cena).
Greg A. Woods,
@ Greg - Eu nunca cheguei a jogar com um PDP-11, receio. Nem um 8051 - fiz algum trabalho incorporado por um tempo, mas isso estava usando um chip da família 8096. Eu só dei uma olhada aqui - interessante. Ouvi falar da arquitetura de Harvard antes de algum tempo, mas não fazia ideia de que havia algo assim muito popular e ainda em uso.
Steve314
4

Vinte anos atrás, isso era importante, mas não tanto agora - há muito mais camadas de abstração entre software e hardware moderno.

É útil saber coisas como precisar de vários threads para tirar proveito de vários núcleos ou que usar mais memória do que existe no sistema é uma coisa ruim, mas além disso, você realmente não precisa disso, a menos que seja seu trabalho escrever essas abstrações camadas.

O restante da sua pergunta sugere que você pode estar mais preocupado com o compilador do que com o hardware, que é um pouco diferente. Você pode encontrar casos em que isso é importante, mas esses tendem a ser triviais (a recursão infinita não funciona muito bem) ou o tipo de casos extremos em que você pode se sentir bem em resolvê-lo, mas provavelmente nunca terá o mesmo problema novamente.

Tom Clarkson
fonte
Sim, você está certo, estou mais preocupado com o compilador. Agradecemos também a sua sugestão sobre vários threads, múltiplos núcleos, etc. Acabou de entrar no meu arquivo de notas do toLearn.
quer
O multithreading @bev é fácil de aprender, apenas não o faça, a menos que você realmente precise e mesmo assim não o faça. mais problemas do que vale a pena na minha experiência.
Skeith 18/10/11
@ Skeith - obrigado pela dica. Vou manter isso em mente.
Bev
4

Ajuda muito a conhecer e entender a abstração apresentada pelo hardware, e um pouco da idéia geral sobre como essa ilusão é criada - mas tentar realmente entender como o hardware moderno realmente funciona é uma tremenda quantidade de trabalho a partir do qual você ' é provável que tenha apenas um retorno mínimo.

Se você perdoa um desvio menor: isso me lembra algo que notei há alguns anos atrás. Décadas atrás (até o final dos anos 70), a maioria das pessoas pensava que os computadores estavam um passo à frente da mágica - dificilmente afetados pelas leis da física, capazes de todo tipo de coisa que fazia pouco sentido real, e assim por diante. Na época, passei um bom tempo tentando (principalmente sem sucesso) convencer as pessoas de que não, elas não eram mágicas. Na verdade, eram máquinas razoavelmente comuns que faziam um número limitado de coisas com muita rapidez e confiabilidade, mas eram extremamente mundanas.

Atualmente, a visão da maioria das pessoas sobre computadores mudou. Agora eles são bastante comuns - a ponto de algumas pessoas muito comuns terem uma compreensão prática deles. Apenas por exemplo, um tempo atrás, enquanto eu estava jantando, eu vi / ouvi um garçom e garçonete no intervalo discutindo o que ela deveria receber em seu novo computador. O conselho que ele estava dando era inteiramente razoável e realista.

Minha visão dos computadores também mudou. Eu fui para o Hot Chips e, antes disso, o Fórum do Microprocessador, que remonta a meados dos anos 90. Provavelmente sei mais sobre hardware de microprocessador do que pelo menos 99% dos programadores - e, sabendo o que faço, vou dizer o seguinte: eles não são mais comuns. Eles fazem quase quebrar as leis da física. Eu fiz muitos testes de baixo nível e posso dizer isso com certeza: superar a ilusão criada pela CPU e mostrar como o hardware realmente funciona é muitas vezes incrivelmente difícil. Eu gostaria de poder postar uma foto de uma de nossas configurações com um computador enterrado sob cabos de não menos de quatro analisadores lógicos apenas para medir adequadamente um aspecto de como o cache funciona em uma CPU moderna (para não mencionar uma programação realmente exigente para garantir que o que medimos seja exatamente o que a CPU estava fazendo e nada mais).

Jerry Coffin
fonte
Jerry - obrigado por seus comentários. Sendo um EE, estou mais confortável com o nível do transistor do que com alguns dos níveis mais altos de abstração. Estou realmente me perguntando o que preciso saber para ser um bom programador de C ++.
Bev
Essa imagem parece interessante. Por que você não pode publicá-lo?
Mason Wheeler
@ Bev: Você realmente não precisa saber nada no nível do transistor para ser um bom programador. Essas abstrações existem por um motivo, e você quase sempre pode considerar qualquer coisa em um nível de abstração abaixo do código / montagem da máquina como completamente irrelevante e apenas supor que funcione.
Mason Wheeler
@MasonWheeler: Levei-o onde costumava trabalhar, mas como não trabalho mais lá, obter acesso a ele provavelmente seria um pouco mais difícil (provavelmente não impossível - parei em boas condições, mas mesmo assim. ..)
Jerry Coffin
1

Idiomas diferentes funcionam em diferentes níveis de abstração do hardware. C e C ++ são de nível muito baixo. As linguagens de script, por outro lado, exigem que você saiba menos sobre os detalhes subjacentes.

No entanto, eu ainda diria que, em todos os casos, quanto mais você souber, melhor será o programador. Parte da programação é ser capaz de manipular vários níveis de abstração ao mesmo tempo.

Se você está programando em C ++, precisa ter um bom entendimento de como uma CPU moderna funciona, pelo menos no nível de abstração em que o compilador trabalha. (Há coisas acontecendo dentro da CPU que também são transparentes para o compilador).

Scott Whitlock
fonte
Scott - por "uma boa compreensão de como uma CPU moderna funciona .." você quer dizer como a lógica digital funciona (por exemplo, como mapas de Karnaugh, tabelas verdadeiras e portas AND / OR / NOR / XOR funcionam)? ou você quer dizer quais recursos o compilador usa diretamente (ou seja, registra)?
Bev
Saber mais é bom. O verdadeiro truque, no entanto, é saber que tipo de "mais" dará o maior retorno possível. Saber horários de instruções, por exemplo, não será muito útil quando for quase impossível prever quais instruções seu compilador usará. Aprender a usar um criador de perfil provavelmente fornecerá uma relação custo / benefício muito melhor.
Steve314
11
@ev - Não, acho que você não precisa descer ao nível do portão. Se você conheceu a arquitetura básica (memória, barramento, CPU), como ela carrega uma instrução, a executa, armazena o resultado, etc., você provavelmente está bem. Você também precisa entender como o compilador distribui o espaço de memória de um programa, incluindo como ele usa a pilha e o heap.
Scott Whitlock
@ ScottWhitlock - Obrigado - este é apenas o tipo de recomendação específica que eu estava procurando.
Bev
0

Gostaria de acrescentar um ponto sobre o design geral de linguagens de nível superior como C.

Em geral, acho seguro dizer que essas linguagens podem ser vistas como implementando uma máquina abstrata e, de fato, foi assim que o próprio Dennis Ritchie descreveu como C funciona e como o design específico da máquina abstrata de C a tornou uma linguagem mais portátil. Como tal, ter algum entendimento da arquitetura do computador e do funcionamento no nível da máquina, pode ser extremamente útil para entender também a máquina abstrata de uma linguagem.

Documento da DMR Portabilidade de programas C e o sistema UNIX é o primeiro que lembro de discutir o modelo de máquina (abstrato) para C.

Acho que o artigo da DMR sobre a história e o desenvolvimento de C também é extremamente útil para mostrar como o hardware real afeta o design da linguagem e talvez seja também um exemplo do design inicial da linguagem de programação: The Development of the C Language

Greg A. Woods
fonte
Como você é novo por aqui, parece que este é um fórum, certamente não é. Suas respostas a uma pergunta não devem ser um ponto que você adiciona, devem ser relegadas a comentários e a resposta deve tentar ser uma resposta abrangente diretamente à pergunta. Dito isso, você está fazendo uma boa observação e isso é valioso nas informações do tópico, talvez se você pudesse colocar algumas linhas nessa resposta à pergunta diretamente junto com esta explicação, seria ótimo. Informações legais que você está compartilhando aqui. Bem-vindo aos programadores!
Jimmy Hoffa
os comentários não têm versão e não são permanentes; portanto, são inúteis para adicionar a um conjunto de respostas. A maioria dos pôsteres também é propensa a ignorar o uso de comentários para atualizar suas respostas, e a maioria das respostas não é marcada como resposta "wiki da comunidade" e, portanto, não pode ser editada por terceiros de forma a manter alguma atribuição ao (s) colaborador (es) subsequente (s) . Além disso, essa questão em particular iniciou uma verdadeira discussão e, gostemos ou não, é assim que algumas dessas coisas acontecem. Tentar forçar todas as contribuições em um molde é uma falha importante do conceito de troca de pilha.
Greg A. Woods,
e, aliás, eu realmente respondi, embora implicitamente, a única pergunta verdadeira do OP: deve-se ter uma compreensão suficiente do hardware para poder modelar a máquina abstrata no centro do design de uma linguagem.
Greg A. Woods,