Que exemplos específicos estão há de saber C fazendo de você um melhor programador de alto nível?

StackOverflow https://stackoverflow.com/questions/2077913

  •  21-09-2019
  •  | 
  •  

Pergunta

O que eu sei sobre a existência de questão, tais como este e este.Deixe-me explicar.

Afet leitura de Joel artigo De volta ao Básico e vendo muitas perguntas semelhantes sobre ISSO, comecei a me perguntar o que são específicos exemplos de situações onde o saber coisas como C pode fazer de você um melhor programador de alto nível.

O que eu quero saber é se há muitos exemplos como esse.Muitas vezes, a resposta a esta questão é algo como "Sabendo C dá a você uma idéia melhor do que está acontecendo nos bastidores"ou "Você precisa de uma base sólida para o seu programa"e essas respostas não têm muito significado.Eu quero entender as diferentes maneiras específicas em que você vai se beneficiar de saber baixo nível de conceitos,

Joel deu um par de exemplos:Binário de bancos de dados XML vs, e cadeias de caracteres.Mas dois exemplos realmente não justificar a aprendizagem de C e/ou Montagem.Então a minha pergunta é esta: Que exemplos específicos estão há de saber C fazendo de você um melhor programador de alto nível?

Foi útil?

Solução

Minha experiência em ensinar alunos e trabalhar com pessoas que estudaram apenas idiomas de alto nível é que eles tendem a pensar em um certo nível de abstração e assumem que "tudo vem de graça". Eles podem se tornar programadores muito competentes, mas eventualmente precisam lidar com algum código que tenha problemas de desempenho e depois os mordê -los.

Quando você trabalha muito com C, pensa em alocação de memória. Você costuma pensar no layout da memória (e na localidade do cache, se isso for um problema). Você entende como e por que certas operações gráficas custam muito. Quão eficientes ou ineficientes são determinados comportamentos de soquete. Como os buffers funcionam, etc. Sinto que o uso das abstrações em uma linguagem de nível superior quando você sabe como é implementado abaixo das capas às vezes oferece "esse molho secreto extra" ao pensar em desempenho.

Por exemplo, o Java tem um coletor de lixo e você não pode atribuir diretamente diretamente as coisas à memória. E, no entanto, você pode fazer certas escolhas de design (por exemplo, com estruturas de dados personalizadas) que afetam o desempenho devido aos mesmos motivos pelos quais isso seria um problema em C.

Além disso, e geralmente, sinto que é importante que um programador de energia não apenas conheça a notação Big-O (que a maioria das escolas ensina), mas que nas aplicações da vida real a constante também é importante (que as escolas tentam ignorar) . Minha experiência anedótica é que as pessoas com habilidades em ambos os níveis de idioma tendem a entender melhor a constante, talvez por causa do que descrevi acima.

Além disso, muitos sistemas de nível superior que eu vi interface com bibliotecas e infraestruturas de nível inferior. Por exemplo, algumas comunicações, bancos de dados ou bibliotecas de gráficos. Alguns drivers para certos dispositivos, etc. Se você é um programador de energia, pode ter que ter essencialmente se aventurar por aí e isso ajuda pelo menos uma idéia do que está acontecendo.

Outras dicas

Sabendo baixo nível coisas que podem ajudar muito.

Para se tornar um piloto de corrida, você tem que aprender e entender a física básica de como pneus, a aderência à estrada.Qualquer pessoa pode aprender a dirigir muito rápido, mas você precisa de uma boa compreensão dos "de baixo nível" coisas (e forças de atrito, linhas de corrida, multa de acelerador e freio de controle, etc) para obter esses últimos por cento de desempenho que permitirá que você para ganhar a corrida.

Por exemplo, se você entender como a arquitetura de CPU trabalha em seu computador, você pode escrever um código que funciona melhor com ele (por exemplo,se você sabe que você tem um determinado tamanho de cache da CPU ou um determinado número de bytes em cada linha de cache da CPU, você pode organizar suas estruturas de dados e a forma de acessá-los a fazer o melhor uso do cache - por exemplo, o processamento de muitos elementos de um array em ordem é muitas vezes mais rápido do que o processamento de elementos aleatórios, devido ao cache da CPU).Se você tem um computador multi-core e, em seguida, compreender como o baixo nível de técnicas de como enfiar o trabalho pode deram enormes benefícios (assim como não entender o baixo nível pode levar a desastres no threading).

Se você entender como e/S de Disco e cache funciona, você pode modificar o arquivo de operações para trabalhar bem com ele (por exemplo,se você ler de um arquivo e escrever para o outro, trabalhando em grandes lotes de dados na memória RAM pode ajudar a reduzir a e/S de contenção entre a leitura e a escrita fases de seu código, e melhorar consideravelmente a taxa de transferência)

Se você entender como funções virtuais de trabalho, você pode criar o código de alto nível que usa funções virtuais bem.Se usada incorretamente, eles podem prejudicar severamente o desempenho.

Se você entender como o desenho é tratada, você pode usar truques inteligentes para melhorar a velocidade de desenho.exemplo:Você pode desenhar um tabuleiro de xadrez, por alternadamente desenho 64 branco e preto quadrados.Mas é muitas vezes mais rápido para desenhar 32 branco sqares e, em seguida, 32 negros (porque você só tem de alterar o desenho de cor duas vezes em vez de 64 vezes).Mas você pode realmente chamar a todo o conselho preto, então XOR 4 listras em toda a placa e 4 listras para baixo a placa em branco, e isso pode ser muito mais rápido ainda (2 cor alterações, e a apenas 9 retângulos para desenhar em vez de 64).Este tabuleiro de xadrez truque ensina muito importante a habilidade de programação:Pensamento Lateral.Ao projetar seu algoritmo de bem, muitas vezes você pode fazer uma grande diferença para o quão bem o programa opera.

Entender C, ou, nesse caso, qualquer linguagem de programação de baixo nível, oferece a você a oportunidade de entender coisas como o uso da memória (ou seja, por que é uma coisa ruim criar vários milhões de objetos pesados), como funcionam os ponteiros/referências de objetos, etc.

O problema é que, como criamos níveis cada vez maiores de abstração, nos encontramos fazendo muita programação de 'LEGO Block', sem entender como os Legos realmente funcionam. E por ter recursos quase infinitos, começamos a tratar a memória e os recursos como a água e tendemos a resolver problemas jogando mais ferro na situação.

Embora não se limite a C, há um tremendo benefício em trabalhar em um nível baixo, com sistemas restringidos de memória muito menores, como o Arduino ou os processadores de 8 bits da velha escola. Ele permite que você experimente perto da codificação de metal em um pacote muito mais acessível e, depois de gastar o tempo, apertando os aplicativos em 512k, você se encontrará aplicando essas habilidades em um nível maior na sua programação diária.

Portanto, o idioma em si não é importante, mas ter uma apreciação mais profunda de como todos os bits se reúnem e como trabalhar efetivamente em um nível mais próximo do hardware é um conjunto de habilidades benéficas para qualquer desenvolvedor de software.

Por um lado, conhecer C ajuda você a entender como a memória funciona no sistema operacional e em outros idiomas de alto nível. Quando seus balões do programa C# ou Java no uso da memória, entendendo que as referências (que são basicamente apenas ponteiros) também se lembram da memória e entendem quantas das estruturas de dados são implementadas (que você obtém de fazer o seu próprio em c) Ajuda a entender que Seu dicionário está reservando enormes quantidades de memória que não são realmente usadas.

Por outro lado, o conhecimento de C pode ajudá -lo a entender como usar os recursos do sistema operacional de nível inferior. Você não precisa disso com frequência, mas às vezes pode precisar de arquivos mapeados de memória ou usar o Marshalling em C#, e C ajudará a entender muito o que está fazendo quando isso acontecer.

Acho que C também ajudou minha compreensão dos protocolos de rede, mas não posso colocar meu dedo em exemplos específicos. Eu estava lendo outra pergunta, então, outro dia em que alguém estava reclamando de como os campos de bits de C são "basicamente inúteis" e eu estava pensando em como os campos de bits elegantes C representam protocolos de rede de baixo nível. Idiomas de alto nível que lidam com estruturas de bits sempre acabam uma bagunça!

Em geral, quanto mais você souber, melhor programador será.

No entanto, às vezes conhecendo outro idioma, como C, pode fazer você fazer a coisa errada, porque pode haver uma suposição que não é verdadeira em uma linguagem de nível superior (como Python ou PHP). Por exemplo, pode -se assumir que encontrar o comprimento de uma lista pode estar o (n) onde n é o comprimento da lista. No entanto, esse provavelmente não é o caso em muitas instâncias de idioma de alto nível. Em Python, para a maioria das coisas semelhantes a listas, o custo é O (1).

Saber mais sobre as especificidades de um idioma ajudará, mas saber mais em geral pode levar a que fazia suposições incorretas.

Apenas "conhecer" C não te tornaria melhor.

Mas, se você entende a coisa toda, como os binários nativos funcionam, como a CPU funciona com ela, quais são as limitações da arquitetura, você pode escrever um código que é mais fácil para a CPU.

Por exemplo, como os caches L1/L2 afetam seu trabalho e como você deve escrever seu código para ter mais acertos em caches L1/L2. Ao trabalhar com C/C ++ e fazer otimizações pesadas, você terá que ir a esse tipo de coisa.

Não é tanto conhecer C, como é que C está mais próximo do metal nu do que muitas outras línguas. Você precisa estar mais ciente de como alocar/desalocar memória, porque precisa fazer isso sozinho. Fazer isso mesmo ajuda a entender as implicações de muitas decisões que você toma.

Para mim, qualquer idioma é aceitável, desde que você entenda como o compilador/intérprete (basicamente) mapeia seu código na máquina. É um pouco mais fácil fazer em um idioma que expõe isso diretamente, mas você deve ser capaz, com um pouco de leitura, descubra como a memória é alocada e organizada, que tipo de padrões de indexação são mais ideais do que outros, quais construções são mais eficiente para aplicações específicas, etc.

Penso mais importante, é uma boa compreensão dos sistemas operacionais, arquiteturas de memória e algoritmos. Se você entende como seu algoritmo funciona, por que seria melhor escolher um algoritmo ou estrutura de dados em detrimento de outra (por exemplo, hashset vs. list) e como seu código é mapeado na máquina, não deve importar qual idioma você está usando .

Esta é a minha experiência de como eu aprendi e me ensinei programando, especificamente, entendendo C, isso está voltando para o início dos anos 90, por isso pode ser um pouco antigo, mas a paixão e o impulso são importantes:

  • Aprenda a entender os princípios de baixo nível do computador, como a programação EGA/VGA, aqui está um link para o arquivo Simtel no guia do programador C para o PC.
  • Entendendo como o trabalho da TSR
  • Baixar todo o arquivo de Trechos de Bob Stout que é uma grande coleção de código C que faz apenas uma coisa - estuda -os e entenda, não sozinho que a coleção de trechos se esforça para ser portátil.
  • Navegue no Concurso Internacional de Código C Ofusado (Ioccc) on -line, e veja como o código C pode ser abusado e entender as intracies do idioma. O pior abuso de código é o vencedor! Faça o download dos arquivos e estude -os.
  • Como eu, eu amei o infame tutorial C de Ponzo, que me ajudou imensamente, infelizmente, o arquivo é muito difícil de encontrar. Se alguém souber de onde obtê -los, deixe um comentário e alterarei esta resposta para incluir o link. Há outro que me lembro - o tutorial [genérico?] C de Coronado, novamente, minha memória sobre isso é nebulosa ...
  • Veja o diário do Dr. Dr. Dobb aqui - Não sei se você ainda pode imprimir, mas eles eram um clássico, lembre -se da sensação de segurar uma cópia impressa na minha mão e arrancar em casa para digitar o código para ver o que acontece!
  • Pegue uma cópia antiga de Turbo C v2 O que acredito que você pode obter do Borland.com e apenas brincar com a programação de 16 bits C para sentir e mexer com os ponteiros ... Claro que é antigo e antigo, mas brincar com dicas nisso é bom.
  • Entender e aprender ponteiros, link aqui para o legado Simtel.net - Um link crucial para alcançar o guru da falta de uma palavra melhor, você também encontrará uma série de downloads referentes à linguagem de programação C - lembro -me de realmente pedir o arquivo de CD Simtel e procurar o material C ...

Algumas coisas com as quais você deve lidar diretamente em C que outros idiomas abstraem de você incluem gerenciamento explícito de memória (malloc) e lidar diretamente com ponteiros.

Minha namorada é um semestre de se formar no MIT (onde eles usam principalmente Java, Scheme e Python) com um diploma de ciência da computação, e atualmente está trabalhando em uma empresa cuja base de código está em C ++. Nos primeiros dias, ela teve dificuldade em entender todos os ponteiros/referências/etc.

Por outro lado, achei muito fácil mover-se de C ++ para Java, porque nunca fiquei confuso sobre as referências de passagem por valor versus referência.

Da mesma forma, em C/C ++, é muito mais aparente que os primitivos são apenas o compilador que trata os mesmos conjuntos de bits de maneiras diferentes, em oposição a um idioma como Python ou Ruby, onde tudo é um objeto com suas próprias propriedades distintas.

Um exemplo simples (não totalmente realista) para ilustrar alguns dos conselhos acima. Considere o aparentemente inofensivo

while(true)
   for(Iterator iter = foo.iterator(); iter.hasNext();)
       bar.doSomething( iter.next() )

ou o nível ainda mais alto

while(true)
    for(Baz b: foo)
        bar.doSomething(b)

Um possível problema aqui é que cada vez em volta do enquanto Loop um novo objeto (o iterador) é criado. Se tudo o que você se importa é a conveniência do programador, o último é definitivamente melhor. Mas se o loop tiver que ser eficiente ou a máquina for restrita ao recurso, você está praticamente à mercê dos designers do seu idioma de alto nível.

Por exemplo, uma reclamação típica para fazer Java de alto desempenho está fazendo parada de execução enquanto o lixo (como todos os objetos de iterador alocados) é recuperado. Não é muito bom se o seu software estiver carregado de rastrear mísseis recebidos, empoltar automaticamente um jato de passageiros ou simplesmente não deixar o usuário se perguntando por que a GUI parou de responder.

Uma solução possível (ainda na linguagem de nível superior) seria enfraquecer a conveniência do iterador para algo como

Iterator iter = new Iterator();
while(true)
    for(foo.initAlreadyAllocatedIterator(iter); iter.hasNext();)
       bar.doSomething(iter.next())

Mas isso só faria sentido se você tivesse uma idéia da alocação de memória ... caso contrário, parece uma API desagradável. A conveniência sempre custa em algum lugar, e saber que coisas de nível inferior podem ajudá-lo a identificar e mitigar esses custos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top