Quais são alguns conceitos / técnicas / recursos de linguagem que todo programador C decente deve conhecer / estar ciente (exclua a engenharia geral de software e similares e se concentre apenas em coisas específicas de C). Gostaria de saber para poder preencher algumas lacunas possíveis no meu conhecimento em C.
Comece com as perguntas C do Stack Overflow e veja se há algo que você não sabe.
Chrisaycock
3
Programador AC provavelmente deve saber que2 + 2 = 4
Edward Estranho
21
Eles deveriam conhecer uma loja que vende sapatos à prova de balas.
Adam Crossland
1
Existem centenas de livros escritos sobre esse assunto. Sua pergunta é realmente bastante vaga. Você precisará ser mais específico para obter respostas decentes, que não são apenas uma lista de coisas. E vendo as respostas geradas até agora a partir desta pergunta, acho que ela precisa ser reformulada ou fechada.
1511 Walter Walter
2
Outra linguagem de programação?
Muhammad Alkarouri 15/02
Respostas:
19
Específico para C? Além das construções padrão comuns à maioria das linguagens procedurais, eu teria que dizer:
(ab) usando o pré-processador
vinculador vs compilador
Ponteiros Ponteiros Ponteiros!
Como matrizes são ponteiros são matrizes
Como as strings C funcionam e como também são ponteiros e matrizes
Quão ruim o uso da string C pode resultar em estouros de buffer
Como converter qualquer coisa para qualquer coisa (é tudo apenas 1s e 0s, afinal :))
Gerenciamento de memória manual malloc / free
Stack vs Heap
Aliasing de ponteiro (por que é ilegal em C99)
Pensando no desenvolvimento em termos de módulos (arquivos .h / .c) com um conjunto de funções expostas publicamente em vez de estritamente classes
O programador de CA deve conhecer ... outras línguas! ;-) É sempre proveitoso conhecer conceitos de outras linguagens de vários paradigmas, como OOP, programação funcional, etc.
Mais seriamente, dar uma olhada no concurso de programação ofuscado é divertido e, curiosamente, também é uma boa experiência.
Mencionei "buffer overflows" em um comentário à resposta de Pythagras, provavelmente devo esclarecer um pouco o que eu quis dizer. Em C, não basta saber que trabalhar diretamente com a memória é perigoso - você também deve entender as maneiras precisas de como é perigoso. Eu realmente não gosto da metáfora de "dar um tiro no pé" para todos esses casos - na maioria das vezes, não é você que puxa o gatilho, mas muitas vezes é um ator com interesses contrários aos seus e / ou dos de seus usuários. .
Por exemplo, em uma arquitetura com uma pilha descendente (as arquiteturas mais populares se encaixam nessa conta - x86 e ARM geralmente incluídos), quando você chama uma função, o endereço de retorno da função será colocado na pilha após as variáveis locais definidas no corpo da função. Portanto, se você declarar um buffer como variável local e expor essa variável ao mundo externo sem verificar o estouro de buffer, assim:
void myFn(void){char buf[256];
gets(buf);}
um usuário externo pode enviar uma string que sobrescreve o endereço de retorno da pilha - basicamente, ele pode alterar a idéia de tempo de execução do programa do gráfico de chamada que leva à função atual. Portanto, o usuário fornece uma string que é a representação binária de algum código executável para sua arquitetura, preenchimento suficiente para sobrecarregar a pilha myFne alguns dados adicionais para substituir o endereço de retorno myFne apontar para o código que ele forneceu. Se isso acontecer, quando myFnnormalmente retornaria o controle ao chamador, ele passaria a codificar o código fornecido pelo usuário mal-intencionado. Se você escrever código C (ou C ++) com potencial de exposição a usuários não confiáveis, precisará entender esse vetor de ataque. Você deve entender por que um estouro de buffer na pilha é frequentemente (mas nem sempre) mais facilmente explorável do que um no heap, e deve entender como a memória no heap é organizada (não em muitos detalhes, necessariamente, mas o A idéia de que uma malloc()região possui estruturas de controle ao seu redor pode ajudar a entender por que seu programa trava em outra malloc()ou em free()).
C expõe você a detalhes de baixo nível sobre como sua máquina funciona e fornece a você um controle mais direto sobre sua máquina do que qualquer outro idioma editado pelo usuário hoje em dia. Com grande poder, vem uma grande responsabilidade - você realmente precisa entender esses detalhes de baixo nível para trabalhar com C com segurança e eficácia.
2 + 2 = 4
Respostas:
Específico para C? Além das construções padrão comuns à maioria das linguagens procedurais, eu teria que dizer:
fonte
Entenda os ponteiros e você entenderá os computadores.
fonte
Além da excelente resposta de pythagras,
como escrever (ou pelo menos ler) declarações complicadas, como
char (*(*funcs[4])())[10]
funcs é um array [4] de ponteiros para uma função retornando ponteiro para o array [10] de char
fonte
fonte
O programador de CA deve conhecer ... outras línguas! ;-) É sempre proveitoso conhecer conceitos de outras linguagens de vários paradigmas, como OOP, programação funcional, etc.
Mais seriamente, dar uma olhada no concurso de programação ofuscado é divertido e, curiosamente, também é uma boa experiência.
fonte
Mencionei "buffer overflows" em um comentário à resposta de Pythagras, provavelmente devo esclarecer um pouco o que eu quis dizer. Em C, não basta saber que trabalhar diretamente com a memória é perigoso - você também deve entender as maneiras precisas de como é perigoso. Eu realmente não gosto da metáfora de "dar um tiro no pé" para todos esses casos - na maioria das vezes, não é você que puxa o gatilho, mas muitas vezes é um ator com interesses contrários aos seus e / ou dos de seus usuários. .
Por exemplo, em uma arquitetura com uma pilha descendente (as arquiteturas mais populares se encaixam nessa conta - x86 e ARM geralmente incluídos), quando você chama uma função, o endereço de retorno da função será colocado na pilha após as variáveis locais definidas no corpo da função. Portanto, se você declarar um buffer como variável local e expor essa variável ao mundo externo sem verificar o estouro de buffer, assim:
um usuário externo pode enviar uma string que sobrescreve o endereço de retorno da pilha - basicamente, ele pode alterar a idéia de tempo de execução do programa do gráfico de chamada que leva à função atual. Portanto, o usuário fornece uma string que é a representação binária de algum código executável para sua arquitetura, preenchimento suficiente para sobrecarregar a pilha
myFn
e alguns dados adicionais para substituir o endereço de retornomyFn
e apontar para o código que ele forneceu. Se isso acontecer, quandomyFn
normalmente retornaria o controle ao chamador, ele passaria a codificar o código fornecido pelo usuário mal-intencionado. Se você escrever código C (ou C ++) com potencial de exposição a usuários não confiáveis, precisará entender esse vetor de ataque. Você deve entender por que um estouro de buffer na pilha é frequentemente (mas nem sempre) mais facilmente explorável do que um no heap, e deve entender como a memória no heap é organizada (não em muitos detalhes, necessariamente, mas o A idéia de que umamalloc()
região possui estruturas de controle ao seu redor pode ajudar a entender por que seu programa trava em outramalloc()
ou emfree()
).C expõe você a detalhes de baixo nível sobre como sua máquina funciona e fornece a você um controle mais direto sobre sua máquina do que qualquer outro idioma editado pelo usuário hoje em dia. Com grande poder, vem uma grande responsabilidade - você realmente precisa entender esses detalhes de baixo nível para trabalhar com C com segurança e eficácia.
fonte
Além das outras boas respostas, gostaria de adicionar técnicas de programação defensiva à lista.
Por exemplo, usando declarações no início / fim de funções para verificar o contrato.
fonte