𝖂𝖎ƙ𝖎𝖊

C (linguagem de programação): mudanças entre as edições

(Correcção de link)
(Correcção de link)
(Sem diferença)

Edição das 04h07min de 22 de agosto de 2004

A linguagem de programação C é uma linguagem de programação de baixo nível e padronizada criada na década de 1970 por Ken Thompson e Dennis Ritchie para ser usada no sistema operativo UNIX. Desde então espalhou-se por muitos outros sistemas operativos, e tornou-se numa das linguagens de programação mais usadas. C tem como ponto-forte a sua eficiência e é a linguagem de programação de preferência para o desenvolvimento de software de sistemas, apesar de também ser usada para desenvolver aplicações. É também muito usada no ensino de ciências da computação, mesmo não tendo sido projectada para novatos.

Características

Conceitos gerais

C é uma linguagem de programação relativamente minimalista que opera próximo do hardware, e é mais semelhante à linguagem de programação assembly do que as restantes linguagens. Certamente, C é por vezes referida como uma "assembly portátil". O código de C pode ser compilado para e corrido em quase todos os computadores. C é típicamente chamada de uma linguagem de baixo nível ou de nível médio, indicando assim o quanto perto ela opera com o hardware. Essa propriedade não foi acidental; C foi criada com um objectivo em mente: facilitar a criação de programas extensos com menos erros recorrendo ao paradigma da programação algorítmica ou procedimental, mas sem nunca sobrecarregar o autor do compilador de C, cujo trabalho complica-se ao ter de realizar as características complexas da linguagem. . Para este fim, a linguagem C possui as seguintes características:

  • Uma linguagem nuclear extremamente simples, com funcionalidades não-essenciais, tal como funções matemáticas ou manuseamento de ficheiros, fornecida por um conjunto de biblioteca de rotinas padronizada.
  • A focalização no paradigma de programação procedimental
  • Um sistema de tipos simples que evita várias operações que não fazem sentido
  • Uso de uma linguagem de pré-processamento, o pré-processador de C, para tarefas tais como a definição de macros e a inclusão de múltiplos ficheiros de código-fonte.
  • Um acesso de baixo-nível à memória do computador, através do uso de ponteiros.
  • Parãmetros que são sempre passados por valor para as funções e nunca por referência.
  • definição do alcance lexical de variáveis
  • Registos, (structs), que permite que dados relacionados sejam combinados e manipulados como um todo

Algumas características úteis que faltam à linguagem C mas que são encontradas noutras linguagens incluem:

Apesar da lista de características úteis que C não possui ser longa, isso não tem sido um impedimento à sua aceitação, pois isso permite que novos compiladores de C sejam escritos rapidamente para novas plataformas, e também permite que o programador permaneça sempre em controle do que o programa está a fazer. Isto é o que por várias vezes permite o código de C correr de uma forma mais eficiente que muitas outras linguagens. Tipicamente, só código de assembly "afinado à mão" é que corre mais rapidamente, pois possui um controle completo da máquina, mas avanços na área de compiladores juntamente com uma nova complexidade nos processadores modernos permitiram que a diferença tenha sido rapidamente eliminada. Uma consequência da aceitação geral da linguagem C é que frequentemente os compiladores, bibliotecas e até intérpretes de outras linguagens de nivel maior sejam eles próprios implementados em C.

"Olá, Mundo!" em C

A seguinte aplicação foi publicada na primeira edição de C de K&R, e tornou-se no programa de introdução padrão da maior parte dos livros sobre C. O programa envia o texto "Olá, Mundo!" para a saída padrão (que é normalmente o ecrâ, mas também pode ser um ficheiro, um outro dispositivo qualquer ou até mesmo um bit bucket , dependendo de como a saída-padrão é mapeada na altura em que o programa é executado.


main()
{
    printf("Olá, Mundo!\n");
}

Apesar do programa acima correr correctamente, presentemente origina algumas mensagens de aviso quando compilado com C ANSI. Essas mensagens podem ser eliminadas efectuando umas pequenas alterações no programa original:


#include <stdio.h>

int main(void)
{
    printf("Olá, Mundo!\n");
    return 0;
}

A primeira linha do programa é uma directiva de pré-processamento #include, que causa que o compilador substitua aquela linha pela totalidade do conteúdo do ficheiro (ou outra entidade) a que a directiva se refere. Neste caso o ficheiro padrão stdio.h (que contém protótipos de funções para trabalho com entrada e saída padrão) irá substituir a linha. Os caracteres < > indicam que o ficheiro stdio.h encontra-se no local em que, quando da configuração do compilador, se definiu como padrão para localização dos ficheiros de inclusão (header files, geralmente com a extensão .h).

A linha (não-vazia) seguinte indica que uma função denominada "main" está a ser definida. A função "main" tem um significado especial nos programas de C, pois é a função que é corrida de inicio quando o programa começa . os caracteres {} delimitam a extensão da função. O termo int define a função "main" como sendo uma função que retorna um número inteiro. O termo void indica que a função não aceita parâmetros.

A linha seguinte "chama", ou executa uma função chamada printf; o ficheiro incluido, stdio.h, contém a informação que descreve a forma como a função printf poderá ser chamada. Nesta chamada, é passado à função printf um único argumento, a linha de texto constante "Olá, Mundo!\n"; O \n é traduzido num caracter de "nova linha", que quando se envia para a saída-padrão faz com que o texto seguinte seja escrito na linha imediatamente abaixo. A função printf retorna um valor, um int, mas como não é usado ela é descartada pelo compilador. O depoimento return ordena ao programa a saída da função que se encontra correntemente (neste caso a função main), devolvendo o valor zero à função que a invocou. Como a função actual é a função main, a função que a invocou é seja o que for que iniciou o programa. Por fim, o caracter } indica o fim da função main. Note-se que texto rodeado por /* e */ (comentários de texto) é ignorado pelo compilador. Os compiladores que obedecem à norma C99 também aceitam como comentários as linhas de texto que são precedidos por //.

Tipos

A linguagem C tem um sistema de tipos semelhante ao de alguns descendentes da linguagem Algol, tais como Pascal. Possui tipos para números inteiros de vários tamanhos com e sem sinal, números de ponto flutuante, caracteres e registos (structs). C usa extensivamente ponteiros, um tipo muito simples de referência que guarda a morada dum local na memória. O ponteiro pode ser dereferenciado, uma operação que busca o objecto que se encontra na morada da memória que o ponteiro possui, morada essa que pode ser manipulada através de aritmética de ponteiros. . Durante o tempo de execução, o ponteiro é simplesmente uma morada de máquina tais como aquelas manipuladas em assembly, mas em tempo de compilação possui um tipo complexo que indica o tipo do objecto para onde ele aponta, permitindo que se verifique o tipo de expressões, incluindo ponteiros. Os ponteiros são usados extensivamente em C. O tipo linha de texto de C é simplesmente um ponteiro para uma disposição de caracteres e alocação dinâmica de memória, descrita abaixo, é efectuada através de ponteiros. Os ponteiros em C possuem um valor reservado especial, NULL, que indica que não estão a apontar para uma morada. O uso desse valor como morada é muito útil na construção de várias estruturas de dados, mas causa comportamento não-definido (possivelmente uma falha de sistema) ao ser dereferenciado. Um ponteiro que possui o valor NULL é chamado ponteiro nulo. A linguagem C também fornece um tipo especial de ponteiros, o ponteiro vazio , que se traduz num ponteiro que aponta para um objecto de tipo desconhecido.

A linguagem C também tem apoio a nivel de linguagem para disposições estáticas (de dimensão fixa) de tipos. As disposições de tipos podem parecer ter mais que uma dimensão apesar de serem técnicamente disposições de disposições de tipos. O acesso a disposições de tipos é feito através de ponteiros e aritmética de ponteiros; o nome da disposição é tratado como se fosse um ponteiro que aponta para o início da disposição. Em certas aplicações não é razoável usar-se disposições de tipos de dimensão fixa e por isso a alocação dinâmica de memória pode ser usada para criar disposições de tipos de dimensão variável. (ver armazenamento de dados em baixo).

Como a linguagem C é regularmente usada em programação de baixo-nivel de sistemas, há casos em que é necessário tratar um número inteiro como sendo uma memória, um número de ponto flutuante como sendo um número inteiro ou um tipo de ponteiro como sendo outro. Para estes casos, a linguagem C fornece a capacidade de "moldagem" (também denominado "conversão de tipo"), uma operação que, caso seja possivel, força a conversão de um objecto de um tipo para outro. Apesar de ser por vezes necessário, o uso de conversões de tipo sacrifica alguma segurança oferecida pelo sistema de tipos.

Armazenamento de dados

Problemas da linguagem C

Há uma expressão popular que traduz-se em algo do género: "com C é fácil dar-se tiros no pé". Por outras palavras, C permite que se efectuem operações que são geralmente não muito desejáveis, e consequentemente, muitos erros simples feitos pelo programador não são detectados pelo compilador ou até mesmo durante o tempo de execução. Isso dá aso a que os programas apresentem um comportamento imprevisivel. Um dos problemas é os objectos alocados automática e dinamicamente não serem inicializados; possuem de inicio qualquer que seja o valor que esteja presente no espaço de memória que ocupam aquando da sua criação. Esse valor é completamente imprevisivel e pode variar entre máquinas, execuções do programa ou até entre duas chamadas à mesma função. Se o programa tenta usar um valor não-inicializado, os resultados obtidos são imprevisiveis. Actualmente, a grande maioria dos compiladores detecta e avisa o programador da existência deste tipo de situações. Os ponteiros da linguagem C são uma principal fonte deste tipo de perigo. Por não serem verificados, um ponteiro pode ser definido para apontar para qualquer objecto de qualquer tipo, incluindo código. Como nada impede o programador de escrever para a morada onde o ponteiro aponta, essa acção pode causar efeitos imprevisiveis. Apesar da maior parte dos ponteiros apontar para locais seguros, o seu alvo também pode ser movido para locais inseguros através do uso de aritmética de ponteiros, a memória para onde apontam pode ter sido dealocada e reutilizada (ponteiros pendurados) ou podem ser desinicializados (ponteiros selvagens). Outro problema dos ponteiros é que a linguagem C permite a livre conversão entre tipos de ponteiros; de novo, a grande maioria dos compiladores actuais são capazes de lançar avisos sobre isto. Outras linguagens de programação tentam abordar este problema através da imposição de restrições maiores aos tipos de referência. Apesar da linguagem C possuir suporte nativo de disposições estáticas de tipos, ela não verifica se as disposições são indexadas por um índice válido (verificação de limites). Por exemplo, é possivel escrever no 6º elemento de uma disposição de 5 tipos, o que tem como efeito resultados imprevisiveis. Isto é chamado de buffer overflow. Apesar disto ser fiel à filosofia da linguagem C de dar ao programador controle total, também tem vindo a ser uma fonte de inúmeros problemas de segurança em servidores de redes baseados na linguagem C. Outro problema comum na linguagem C é não ser possivel a reutilização da memória da pilha sem antes ter sido explicitamente libertada pelo programador através da função free(). O resultado disto é que se o programador se esquecer acidentalmente de libertar a memória, mas continuar a alocá-la, cada vez mais memória será consumida desnecessáriamente ao longo do tempo. Esta situação é chamada de fuga de memória. Também é possivel que aconteça o problema inverso, ou seja, libertar memória cedo demais e continuar a usá-la. Como o sistema de alocação de memória pode reutilizar a memória em qualquer momento por motivos não-relaciondos, isto resulta em comportamento imprevisivel. Estas situações em particular são corrigidas em linguagens de programação que suportem colecção automática de lixo. Tem vindo a ser criadas ferramentas com o intuito de ajudar os programadores a evitar muitos destes tipos de erros quando programam em C. Também existem bibliotecas que efectuam verificação dos limites de disposições de tipos e também uma forma algo limitada de colecção de lixo automática, mas não fazem parte do padrão da linguagem C.

História

Desenvolvimentos iniciais

O desenvolvimento inicial da linguagem C ocorreu nos laboratórios Bell da AT&T entre 1969 e 1973. Segundo Ritchie, o periodo mais creativo ocorreu em 1972. Deu-se o nome "C" à linguagem porque muitas das suas características derivaram de uma linguagem de programação anterior chamada "B". Há vários relatos que se referem à origem do nome "B": Ken Thompson dá crédito à linguagem de programação BCPL mas ele também criou uma outra linguagem de programação chamada 'Bon, em honra da sua mulher Bonnie. Por volta de 1973, a linguagem C tinha-se tornado suficientemente poderosa para que grande parte do núcleo de UNIX, originalmente escrito na linguagem de programação PDP-11/20 assembly, fosse reescrito em C. Este foi um dos primeiros núcleos de sistema operativo que foi implementado numa linguagem sem ser o assembly, sendo exemplos anteriores o sistema Multics (escrito em PL/I) e TRIPOS (escrito em BCPL).

C de K&R

Em 1978, Ritchie e Brian Kernighan publicaram a primeira edição do livro The C Programming Language. Esse livro, conhecido pelos programadores de C como "K&R", serviu durante muitos anos como uma especificação informal da linguagem. A versão da linguagem C que ele descreve é usualmente referida como "C de K&R". (A segunda edição do livro cobre o posterior padrão ANSI C, descrito abaixo.) K&R introduziram as seguintes características na linguagem:

  • tipos de dados struct
  • tipos de dados long int
  • tipos de dados unsigned int
  • O operador =+ foi alterado para +=, e assim sucessivamente (o analizador léxico do compilador confundia o operador =+. Por exemplo, i =+ 10 e i = +10).

C de K&R é frequentemente considerado a parte mais básica da linguagem que é necessário que um compilador de C suporte. Durante muitos anos, mesmo após a introdução do padrão C ANSI, ele era considerado o "menor denominador comum" que programadores de C se apoiavam quando uma portabilidade máxima era desejada, desde que nem todos os compiladores eram actualizados para apoiar na integra o padrão C ANSI, e código C de K&R razoavelmente bem escrito é também legal em C ANSI. Nos anos que se seguiram à publicação do C K&R, algumas características "não-oficiais" foram adicionadas à linguagem, suportadas por compiladores da AT&T e de outros vendedores. Estas incluiam:

  • funções void e tipos de dados void *
  • funções que retornam tipos struct ou union
  • campos de nome struct num espaço de nome separado para cada tipo struct
  • atribuição a tipos de dados struct
  • qualificadores const para criar um objecto só de leitura
  • uma biblioteca-padrão que incorpora grande parte da funcionalidade implementada por vários vendedores
  • enumerações
  • o tipo de ponto-flutuante de precisão simples

C ANSI e C ISO

Durante os finais da década de 1970, a linguagem C começou a substituir a linguagem BASIC como a linguagem de programação de microcomputadores mais usada. Durante a década de 1980, foi adoptada para uso no PC IBM, e a sua popularidade começou a aumentar significativamente. Ao mesmo tempo, Bjarne Stroustrup juntamente com outros nos laboratórios Bell começou a trabalhar num projecto onde se adicionava construcções de linguagens de programação orientada por objectos à linguagem C. A linguagem que eles produziram, chamada C++, é nos dias de hoje a linguagem de programação de aplicações mais comum no sistema operativo windows da companhia Microsoft; C permanece mais popular no mundo UNIX. Em 1983, o instituto norte-americano de padrões (ANSI) formou um comité, X3j11, para estabelecer uma especificação do padrão da linguagem C. Após um processo longo e árduo, o padrão foi completo em 1989 e ratificado como ANSI X3.159-1989 "Programming Language C". Esta versão da linguagem é frequentemente referida como C ANSI. Em 1990, o padrão C ANSI, após sofrer umas modificações menores, foi adoptado pela Organização Internacional de Padrões (ISO) como ISO/IEC 9899:1990. Um dos objectivos do processo de padronização C ANSI foi o de produzir um sobreconjunto do C K&R, incorporando muitas das características não-oficiais subsequentemente introduzidas. Entretanto, muitos programas tinham sido escritos e que não compilavam em certas plataformas, ou com um certo compilador, devido a

  • o uso de bibliotecas não-padrão (por exemplo, interfaces gráficos)
  • alguns compiladores não aderirem ao padrão C ANSI, ou ao seu sucessor, no seu modo por defeito.

C99

Após o processo ANSI de padronização, as especificações da linguagem C permaneceram relativamente estáticas por algum tempo, enquanto que a linguagem C++ continuou a evoluir. (em 1995, a Normative Amendment 1 criou uma versão nova da linguagem C mas esta versão raramente é tida em conta.) Contudo, o padrão foi submetido a uma revisão nos fins da década de 1990, levando à publicação da norma ISO 9899:1999 em 1999. Este padrão é geralmente referido como "C99". O padrão foi adoptado como um padrão ANSI em Março de 2000. As novas características do C99 incluem:

  • funções em linha
  • levantamento de restriçõs sobre a localização da declaração de variáveis (como em C++)
  • adição de vários tipos de dados novos, incluindo o long long int (para minimizar a dor da transição de 32-bits para 64-bits), um tipo de dados boolean explicito e um tipo complex que representa números complexos
  • disposições de dados de comprimento variável
  • suporte oficial para comentários de uma linha iniciados por //, emprestados da linguagem C++
  • várias funções de biblioteca novas, tais como snprintf()
  • vários ficheiros-cabeçalho novos, tais como stdint.h

O interesse em suportar as características novas de C99 parece ser variado. Apesar do GCC e vários outros compiladores suportarem grande parte das novas características do C99, os compiladores mantidos pela Microsoft e pela Borland não, e estas duas companhias não parecem estar muito interessadas adicionar tais funcionalidades, ignorando por completo as normas internacionais.

Relações com C++

A linguagem de programação C++ foi originalmente derivada do C. À medida que as linguagens C e C++ foram evoluindo independentemente, a divisão entre as duas tem vindo a aumentar. O padrão C99 criou um número de características que entram em conflito. Hoje, as principais diferenças entre as duas linguagens são:

  • inline - em C++, funções em linha encontram-se no espaço global enquanto que em C encontram-se no espaço do ficheiro. Por outras palavras, isso significa que em C++, qualquer definição de qualquer função em linha (mas sem ser a respeito da sobrecarga de funções de C++) tem de estar em conformidade com a "regra de uma definição" da linguagem C++. Mas em C, a mesma função em linha pode ser definida de maneira diferente em diferentes ficheiros.
  • A palavra-chave bool em C99 encontra-se no seu próprio ficheiro-cabeçalho, <stdbool.h>. Padrões anteriores de C não definiam um tipo booleano, e vários (e incompatíveis) métodos foram usados para simular um tipo booleano.

Algumas características originalmente desenvolvidas em C++ também apareceram em C. Entre elas encontram-se:

  • prototipagem
  • comentários de linha, indicados por //; comentários de linha terminam com um caracter de nova-linha
  • a palavra-chave inline
  • a palavra-chave void
  • tipagem mais forte

Ferramentas de programação

Ver também

Referência

talvez você goste