O que um programador C deve saber? [fechadas]

11

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.

Anto
fonte
9
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
  • Sindicatos
  • Por que o sprintf pode explodir seu pé
  • Ponteiros de função
Doug T.
fonte
Eu adicionaria "estouros de buffer" à lista.
Aidan Cully
@Aidan, boa captura. Adicionado.
Doug T.
2
Como matrizes C e ponteiros não são os mesmos: books.google.ca/…
Matthieu
ponteiros deveria ter sido repetido pelo menos 3 vezes mais
Gaurav
8

Entenda os ponteiros e você entenderá os computadores.

PP.
fonte
12
Nah, você simplesmente terá uma ilusão de que entende computadores.
Job
4

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

tcrosley
fonte
1
Se ficar tão complexo, talvez isso pertença a um comentário?
Job
7
talvez ele devesse aprender a evitar escrever assim?
FabianB
3
  1. Regras de promoção de número inteiro
  2. Inicialize tudo com um valor conhecido
  3. GOTO não é ruim, especialmente quando usado para lidar com exceções / falhas
  4. malloc e / ou calloc podem retornar NULL ... verifique se os valores de retorno do seu cheque
  5. Alocações freqüentes de memória pequena podem causar fragmentação no heap.
  6. Aritmética do ponteiro
  7. Máscaras de bits são seu amigo
  8. x >> 1 é equivalente a x / 2 para números inteiros não assinados
Pemdas
fonte
+1 para GOTO não ser mal :)
zvrba
2

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.

PhiLho
fonte
2

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.

Aidan Cully
fonte
0

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.

AndersK
fonte