Apesar de ser flexível, C tem alguns "drawbacks" que não são muito explícitos.
Um programa que abusa dos pontos fracos da linguagem tem o potencial de
causar problemas, mas pode compilar sem nenhuma warning. Aqui estão as
limitações do C:
Namespace extremamente sujo e nomes de identificadores.
Verificação relaxada de tipos de dados.
Ausência completa de verificação de limites.
Namespace sujo e nomes de identificadores.
Um espaço de nomes define um limite onde os nomes de identificadores podem ser
declarados. Em C, o espaço de nomes é sempre global ou dentro do escopo de um bloco.
Esta limitação traz um problema sério para aqueles que adoram usar variáveis globais.
Pode acontecer que uma determinada variável global entre em conflito com outra que
exista dentro de uma biblioteca, por exemplo, o que pode levar o programa a ter um
comportamento completamente fora do esperado e sem uma causa clara mesmo em sessões
de depuração. O efeito é que a variável muda seu conteúdo sem uma operação aparente.
O melhor é sempre evitar de criar variáveis globais. Se for imprescindível, tente
prefixá-la com o nome do sistema, módulo, uma sigla, algo que você julgue que seja
único. Variáveis globais, via de regra, denotam design ruim de um aplicativo. É
totalmente possível viver sem elas. Apenas em alguns casos muito particulares é
que se tem de lançar mão deste recurso, por não haver outra alternativa: tratamento
de eventos assíncronos. Por exemplo, um handle de sinal que precisa salvar um status
para uso posterior. Via de regra esse handle vai ter de lidar com alguma coisa que
precisa ser persistido e que precisa ter seu status alterado de forma assíncrona,
sem a intervenção direta do programa.
Um erro comum, também, está na forma como se define nomes. É comum ver
programadores iniciando nomes com caractere sublinhado com a primeira letra seguinte
maiúscula. O compilador não reclama desta prática mas o comitê ANSI-X3J11 convencionou
que nomes que seguem esta linha são reservados ao implementador da biblioteca
Standard C. Em outras palavras: evite de iniciar nomes com o caractere sublinhado
tendo a segunda letra em maiúsculas.
Outra dica importante: a linguagem C suporta identificadores com, no máximo,
32 caracteres. Além dos 32 caracteres, o compilador trunca os nomes. Se dois nomes
distintos tiverem os primeiros 32 caracteres iguais, o compilador irá tratá-los
como o mesmo nome, o que pode gerar conflitos. Portanto, evite identificadores
muito compridos.
Verificação relaxada de tipos de dados
O comitê ANSI tentou contornar este problema criando os protótipos de funções.
Os protótipos de funções são uma forma de forçar o compilador a realizar uma
checagem mais rígida dos parâmetros e tipos de retorno. Porém, o máximo que irá
acontecer é o compilador lhe dar uma warning. É perfeitamente possível chamar uma
função que espera receber um ponteiro para char com um número inteiro. Isso gera
um executável que provavelmente fará alguma bobagem na memória.
Portanto, tome extremo cuidado com as atribuição dentro do seu código. Usar
casts faz somente com que o compilador pare de reclamar. A melhor idéia é simplesmente
verificar se os tipos são realmente compatíveis e usar do bom senso sempre.
Ausência de verificação de limites
Esta é uma característica dos vetores. Se o seu programa passar do fim de um
vetor, passou. Vai acessar na memória sabe Deus lá o que. Tome extremo cuidado
ao escrever rotinas que utilizem vetores, principalmente rotinas que trabalham
com cadeias de caracteres. É muito comum em programas C esquecerem de que o fim
de uma string precisa ter o caractere '\ 0'. Se o nosso querido '\ 0' não estiver
dentro do vetor, significa que a string está aberta e um simples strcpy pode causar
uma catástrofe no seu programa.
[2] Comentário enviado por y2h4ck em 08/06/2004 - 08:16h
Certos casos nem mesmo o {COMENTARIO} pode ajudar eheh. Como o caso de exploracoes avançadas em Memória Adjacente e smashing overflows... mesmo tendo controles na variavel pode-se explorar o programa do mesmo jeito...
[3] Comentário enviado por tiago.accon em 08/06/2004 - 11:40h
Perfeito artigo ! A linguagem C, por ser de baixo nível já fala por si própria. Ela é extremamente flexivel, mas para programadores que não são organizados é um perigo iminente. Parabens :] tiago.accon
[4] Comentário enviado por jllucca em 08/06/2004 - 14:03h
Acho a artigo excelente, mas ele fala da linguagem C. Mas, cita coisas de C++ tambem. Acho que todo mundo termina por misturar. Soh nao acho legal o pessoal dizer que ela eh "uma linguagem de baixo nivel que fala por si propria". Depois de muito debater uma pessoa cheguei a conclusao de que linguagens nao tem niveis e nem podemos falar em niveis sem citar parametros comparacao. Mas, isso eh uma picuinha minha mesmo ^^ .
[7] Comentário enviado por ron_lima em 09/06/2004 - 13:38h
Acredito que o pré-requisito para se programar em C é, antes de mais nada, procurar entender bem de algoritmos e estruturas de dados. Este pré-requisito é válido para todas as linguagens de programação, na verdade. A linguagem, propriamente dita, é simples (mas não fácil). C contém apenas 32 palavras reservadas (apesar de que algumas implementações reservam mais nomes). Penso que o segredo para o sucesso no entendimento da linguagem vem, antes de mais nada, de uma boa base de algoritmos e estruturas de dados. O restante é questão de ler um bom livro, como o excelente "A Linguagem C" de Brian Kernighan e Dennis Ritchie, os criadores da linguagem.
[8] Comentário enviado por jayro rodrigues em 10/06/2004 - 19:51h
Eu estou começando em C e percebi a flexibilidade da linguagem. Uma grande dificuldade que estou tendo é no projeto dos programas, ou seja, ALGORITIMO. É aconselhavel que se estude algorítimo primeiramente. VALEU !!!
[9] Comentário enviado por vvega em 21/06/2004 - 10:30h
Muito bom o artigo, mas um pouco confuso para quem eh iniciante, como ja dito aqui nos comentarios. Mas vale o alerta, pois programar em C nao eh la tao facil como alguns dizem, ainda que, tambem, nao seja tao complicado como dizem outros. Que tal ser fizessemos uma apostila (dai um prototipo de um livro) sobre a linguagem C baseada em experiencias de programadores ? Nao seria algo para ensinar o C, mas um documento para quem ja aprendeu o nivel basico (estruturas sequenciais, condicionais e de repeticao, vetores, matrizes, registro, ponteiros, pilhas e filas, por exemplo) e deseja se embrenhar no mundo mais avancado.
[11] Comentário enviado por HackSpy em 10/11/2004 - 16:20h
Acho que a linguagem "C/C++" antes de tudo, deve ser uma linguagem planejada. Não se pode apenas ligar o micro e começar a digitar. Tudo que é feito em cima de analises e programado com competência, com certeza irá gerar algo altamente confiável e rápido. Agora, quando se programa amadoramente o risco é altissímo, um exemplo seria um erro de lógica cujo o compilador na acusa erro algum mas seu sistema complexo não funciona. PLANEJEM !!!!. Parabens pelo artigo.
[12] Comentário enviado por ron_lima em 11/11/2004 - 01:46h
Acredito que esta observação vale para toda e qualquer linguagem de programação. A implementação é apenas uma das fases do desenvolvimento do software e não é a fase principal. Em verdade a análise dos requisitos e o modelamento do problema é que ficam no ponto de destaque. Normalmente, sistemas bem analisados e modelados são aqueles que são entregues no prazo e sem uma quantidade infinita de erros... Sem dúvida, HackSpy, você está coberto de razão! Planejar antes de programar!
[13] Comentário enviado por nick_skyp em 16/01/2005 - 03:50h
Parabens pelo artigo,
...com certeza sem artigos como esse, mtos iniciantes em C, tenham q sofrer um poukinho e conhecer os topicos citados pelo seu artigo sentindo na pele esses tipos de erros... {experiência própria..hehehe :-D}
entao.. axei bastante feliz sua observação qto ao estudo da Standard C, qeria q vc me indicasse algum material sobre ela (apostila, tutorial se possivel em portugues)...
parabeins... teh +!
[14] Comentário enviado por voulogarso1vez em 02/03/2005 - 23:19h
Ih, faltou tanta coisa que poderia ser dita...
*Falta de manipulação de exceções (só setjmp/longjmp, difíceis de usar). Tratamento de erros fica uma mistura feita de códigos de retorno, errno, parâmetros de erro (passados por ponteiro) e setjmp/longjmp para os mais ousados.
*Nenhuma estrutura de dados que cresça automaticamente (não consigo imaginar fazer um programa que manipule muitas strings em C puro: ia ser um inferno, cheio de bugs, falhas de segurança e/ou limites arbitrários nos tamanhos das strings). Estruturas mais automáticas realmente abrem possibilidades de estilos de programação muito mais poderosos.
*Muitos casos de "comportamento indefinido", "dependentes da implementação" que dificultam portar o código.
*Biblioteca padrão extremamente limitada e com funções seriamente mal projetadas (gets é a pior, mas tem a sprintf, strtok, setlocale, strncpy, strcat, errno e todas as funções de entrada de dados são bastante limitadas).
*Se formos comparar com linguagens mais dinâmicas (Lua, Python, Lisp), aí sim C perde feio, sem reflexão, sem funções como valores de primeira classe, sem listas e passagem de parâmetros unificada, sem execução de código a partir de strings, sem hashtables, etc.
[15] Comentário enviado por ron_lima em 06/03/2005 - 07:53h
Setjmp e longjmp não foram projetados para serem tratadores de exceções.A idéia era fornecer à linguagem uma forma de realizar um goto que não fosse local a uma determinada função. Pelo que li no seu comentário, você compara a linguagem C com linguagens orientadas ao objeto, como o Python, e esta é uma comparação infeliz. C é uma linguagem procedural, antes de mais nada. C é uma linguagem de nível médio, ou seja, tem as características do assembly e características de linguagem de nível alto, como as que você citou. No entanto, pense no C como um melhoramento do assembly, ou seja, uma linguagem de programação que tem keywords ao invés de mnemônicos.
[16] Comentário enviado por Herr_Filip em 17/10/2005 - 12:05h
achei muito interessante a leitura, gostei da linha de pensamento da autora.
eu (pelo menos hoje em dia) nao programa em C e meu conhecimento em C é bem pobrezinho, entao começar a estudar a linguagem baseado em textos mais teóricos ajuda bastante! (apenas de que eu já tinha conhecimento de alguns "defeitos", ou... "detalhes" da linguagem que a Autora cita
[18] Comentário enviado por ron_lima em 22/03/2008 - 19:42h
Na verdade, a sintaxe do java assemelha-se muito com a da linguagem C. Obviamente, a primeira diferencia-se pelo fato de ser orientada ao objeto, coisa não suportada pela linguagem C.
C é uma linguagem muito antiga, já com 38 anos de idade, ao passo que java popularizou-se no fim dos anos 90 no século passado. Cada linguagem tem seu nicho de uso. Por exemplo, você jamais escreveria um device driver em java devido às limitações impostas pela linguagem.
[19] Comentário enviado por canguru em 03/01/2010 - 19:32h
Ei...só para constar....a linguagem mais flexível do mundo é o assembly....nada é mais flexível q ele.....pois com ele vc se comunica direto com a maquina...se vc quer botar algo no video...vc tem q mandar uma interupção para a placa de video.....quer pegar algo do teclado..a mesma coisa.....
[20] Comentário enviado por ron_lima em 04/01/2010 - 06:57h
Desculpe por discordar, Canguru. Não confunda os recursos de uma linguagem com sua flexibilidade. Assembly é uma das linguagens mais inflexíveis que existem. A flexibilidade está ligada ao fato da linguagem permitir a descrição de estruturas e manipulações de dados de maneira fácil e eficaz e não com os recursos que a linguagem lhe dá. C++ é flexível, pois permite que você dê novos significados aos operadores, mas PHP, por exemplo, é ainda mais flexível, pois permite que expressões sejam criadas e avaliadas dinamicamente sem muito esforço de programação.