Вы находитесь на странице: 1из 19

Origem da linguagem C Desenvolvida nos laboratrios Bell na dcada de 70, a partir da Linguagem B (criada no final dos anos 60 por

Ken Thompson), que foi reformulada por Brian Kernighan e Dennis M. Ritchie e posteriormente renomeada para C. A linguagem C pode ser considerada uma linguagem de nvel mdio, pois possui instrues que a tornam ora uma linguagem de alto nvel, com sintaxe prxima a linguagem humana, ora pode ser utilizada como uma linguagem de nvel baixo, com instrues que manipulam bits, bytes e endereos de memria bem prximas a linguagem de mquina. A linguagem C foi desenvolvida a partir da necessidade de se escrever programas que utilizassem recursos prprios da linguagem de mquina de uma forma mais simples e portvel que o Assembler. Caractersticas da Linguagem C - Portabilidade entre mquinas e sistemas operacionais. - Dados compostos em forma estruturada. - Programas Estruturados. - Linguagem Compilada. - Total interao com o Sistema Operacional. - Cdigo compacto e rpido, quando comparado ao cdigo de outras linguagem de complexidade anloga. Algumas aplicaes escritas em C - UNIX (Sistema Operacional executvel em micro computadores e em mainframes). - Clipper (Linguagem de programao para desenvolvimento de aplicaes comerciais ). - Planilhas como Lotus 1,2,3 e Excel . - Banco de dados dBase III, IV e Access. - InfoStar (O editor de texto utilizado nos USA no Sistema Operacional UNIX). - FormTool (Editor de formulrios). - Efeitos Especiais de filmes com Star Trek e Star War. - Power Builder e Visual Basic . C comparado a outras linguagens Entende-se como linguagem de alto Nvel como sendo a capacidade da linguagem em compreender instrues escritas em "dialetos" prximos do ingls ( Pascal, Clipper, Visual Basic, Delphi, por exemplo) e baixo Nvel para aquelas linguagens que se aproximam do assembly, que a linguagem prpria da mquina, compostas por instrues binrias e outras incompreensveis para o ser humano no treinado para este propsito. Quanto mais clara uma linguagem for para o humano (simplicidade >) mais obscura ser para a mquina (velocidade <). Antes da linguagem C tornar-se um padro de fato (meados de 1.988, nos USA), tnhamos aproximadamente, o Seguinte perfil de mercado: - Aplicaes de Banco de Dados - Mainframe: COBOL e gerenciadores - Micros: dBase, Clipper e BASIC e gerenciadores como Btrieve - Aplicaes Grficas: Pascal.

- Aplicaes Cientficas: FORTRAN e Pascal. - Utilitrios, Sistemas Operacionais e Compiladores: Assembler. A chegada de poderosos compiladores C (Borland, Microsoft e Zortech-Symantec), revolucionou totalmente estes conceitos pois passou a permitir a construo de praticamente qualquer tipo de aplicao na Linguagem C, normalmente mais rpida do que na linguagem original e portvel entre os diversos ambientes (como em DOS, UNIX, etc.).

O Desenvolvimento da Linguagem C*
Dennis M. Ritchie Bell Labs/Lucent Technologies Murray Hill, NJ 07974 USA
dmr@bell-labs.com

RESUMO
A linguagem de programao C foi inventada no comeo dos anos 70 como uma linguagem de implementao de sistema para o nascente sistema operacional Unix. Derivada da linguagem sem tipos BCPL, ela evoluiu para um modelo estruturado; criada numa minscula mquina como uma ferramenta para melhorar um ambiente de programao escasso, ela tornou-se um das linguagens dominantes de hoje. Este documento estuda sua evoluo.

Introduo
NOTA: *Copyright 1993 Association for Computing Machinery, Inc. Esta reimpresso eletrnica tornou-se disponvel pelo autor como uma cortesia. Para direitos de publicao

adicionais contate a ACM ou o autor. Este artigo foi apresentado na Segunda Conferncia sobre Histria das Linguagens de Programao, Cambridge, Mass., Abril de 1993.

Este documento fala sobre o desenvolvimento da linguagem de programao C, as influncias sobre ela e as condies sob as quais ela foi criada. Por causa da brevidade, eu omiti a completa descrio da linguagem C e suas parentas ancestrais, as linguagens B [Johnson 73] e BCPL [Richards 79], concentrando-me nos elementos caractersticos de cada linguagem e como eles evoluram. A linguagem C tomou existncia nos anos de 1969 - 1973, em paralelo com o primitivo desenvolvimento do sistema operacional Unix; o perodo mais criativo ocorreu durante 1972. Outra inundao de mudanas apareceu entre 1977 e 1979, quando a portabilidade do sistema Unix estava sendo demonstrada. No meio deste segundo perodo, a primeira grande descrio disponvel da linguagem apareceu: A Linguagem de Programao C, freqentemente chamada de 'livro branco' ou 'K&R' [Kernighan 78]. Finalmente, na metade dos anos 80, a linguagem foi oficialmente padronizada pelo comit ANSI X3J11, o qual fez novas mudanas. At o comeo dos anos 80, apesar de existirem compiladores para uma variedade de arquiteturas de mquinas e sistemas operacionais, a linguagem foi quase exclusivamente associada com o Unix; mais recentemente, ela tem difundido-se mais extensamente, e hoje est entre a linguagens mais comumente usada por toda a indstria de computao.

Histria: o cenrio
O final dos anos 60 foi uma era turbulenta para a pesquisa de sistemas de computadores no Bell Telephone Laboratories [Ritchie 78] [Ritchie 84]. A companhia estava saindo do projeto Multics [Organick 75], o qual tinha comeado como um empreendimento conjunto do MIT, General Eletric e Bell Labs; por 1969, a administrao do Bell Labs e igualmente os pesquisadores, chegaram concluso de que as promessas do Multics poderiam ser satisfeitas somente muito depois e tambm muito custosamente. Antes que a mquina Multics GE-645 fosse removida das premissas, um grupo informal, liderado primariamente por Ken Thompson, tinha comeado a investigar alternativas. Thompson queria criar um ambiente de computao confortvel de acordo com seu prprio projeto, usando quaisquer meios disponveis. Seus planos, estando isto evidente em retrospecto, incorporariam muitos dos aspectos inovadores do Multics, incluindo uma notao explcita de um processo como um foco de controle, um sistema de arquivo estruturado em rvore, um interpretador de comandos como um programa ao nvel do usurio, simples representao de arquivos texto e acesso generalizado a dispositivos. Ele excluiu outros, tais como acesso unificado a memria e arquivos. No comeo, alm disso, ele e o resto de ns protelamos outro elemento pioneiro (ainda que no original) do Multics, chamado de escrita quase que exclusiva em linguagem de alto-nvel. A PL/I, a linguagem de implementao do Multics, no era muito do nosso gosto, mas ns estvamos usando outras linguagens, incluindo BCPL, e ns lamentvamos perder as vantagens de escrever programas em uma linguagem acima do nvel do montador, tais como facilidade de escrita e claridade de entendimento. Naquele tempo ns no colocamos muito valor em portabilidade, o interesse nisso surgiu depois. Thompson foi defrontado com um ambiente de hardware restrito e espartano ao mesmo tempo: o DEC PDP-7 na qual ele comeou em 1968 era uma mquina com memria de 8K, o tamanho de palavra era de 18-bits e no havia nenhum software til para ela. Enquanto desejava usar uma linguagem de alto-nvel, ele escreveu o sistema original Unix no montador PDP-7. No comeo, ele nem mesmo fez o programa no PDP-7 propriamente dito, mas ao invs disto usou um conjunto de macros para o montador

GEMAP em uma mquina GE-635. Um ps-processador gerou uma fita de papel legvel pelo PDP-7. Estas fitas foram levadas da mquina GE para o PDP-7 para testar um primitivo kernel do Unix, um editor, um montador, um simples shell (interpretador de comandos) e uns poucos utilitrios (como os comandos Unix rm, cat e cp) foram completados. Aps este ponto o sistema operacional era auto-sustentvel: programas podiam ser escritos e testados sem recorrer a fita de papel, e o desenvolvimento continuou no PDP-7 propriamente dito. O montador PDP-7 de Thompson excedeu o DEC em simplicidade; ele avaliava expresses e emitia os bits correspondentes. No havia bibliotecas, nenhum carregador ou link editor: o fonte inteiro do programa era apresentado ao montador e o arquivo de sada - com um nome fixo - que emergia era diretamente executvel. (Este nome, a.out, explica um pouquinho a etimologia Unix; ele sada do montador. Igualmente aps o sistema ganhar um linker e um conjunto especificando um outro nome explicitamente, ele foi mantido como o resultado executvel default de uma compilao.). No muito depois do Unix rodar no PDP-7, em 1969, Doug Mcllroy criou a primeira linguagem de alto-nvel para o novo sistema: uma implementao da TMG de McClure [McClure 65]. A TMG era uma linguagem para a escrita de compiladores (mais geralmente, TransMoGrifiers) em um estilo top-down e recursivo descendente, combinando sintaxe de notao de livre contexto com elementos procedurais. Mcllroy e Bob Morris tinham usado a TMG para escrever o primitivo compilador PL/I para o Multics. Desafiado pelo feito de Mcllroy na reproduo da TMG, Thompson decidiu que o Unix possivelmente ele no tinha sido chamado assim - necessitava de uma linguagem de programao de sistema. Aps uma rapidamente abandonada tentativa em Fortran, ele criou uma linguagem prpria dele mesmo, o qual ele chamou de B. A linguagem B pode ser pensada como a C sem tipos; mais precisamente, ela a BCPL comprimida em 8K de memria e filtrada pelo crebro de Thompson. Seu nome provavelmente representa uma contrao de BCPL, entretanto uma teoria alternativa pensa que ele deriva de Bon [Thompson 69], uma linguagem no relatada criada por Thompson nos dias do Multics. Bon por sua vez foi nomeada de conformidade com o nome de sua esposa Bonnie, ou (de acordo com uma citao em seu manual) de conformidade com o nome de uma religio cujos rituais envolvem a murmurao de frmulas mgicas.

Origens: as linguagens
A linguagem BCPL foi projetada por Martin Richards no meio dos anos 60 enquanto ele estava visitando o MIT, e foi usada no comeo dos anos 70 para vrios projetos interessantes, dentre eles o sistema operacional OS6 em Oxford [Stoy 72] e partes do trabalho no Xerox PARC [Thacker 79]. Ns tornamo-nos familiarizados com ela porque o sistema MIT CTSS [Corbato 62] na qual Richards trabalhou era usado para desenvolvimento do Multics. O compilador original BCPL foi transportado para o Multics e para o sistema GE-635 GECOS por Rudd Canaday e outros do Bell Labs [Canaday 69]; durante a agonia final da vida do Multics no Bell Labs e imediatamente aps, ela foi a linguagem escolhida pelo grupo de pessoas que estariam envolvidas depois com o Unix. A linguagens BCPL, B e C, ajustam-se firmemente na tradicional famlia procedural simbolizada pela Fortran e Algol 60. Elas so particularmente orientadas para a programao de sistemas, so pequenas e descritas compactamente, sendo amenas para a traduo por compiladores simples. Elas esto 'prximas mquina' na qual as abstraes por elas introduzidas so prontamente fundamentadas nos tipos de dados concretos e operaes providas por computadores convencionais, confiando em

bibliotecas de rotinas para entrada-sada e outras interaes com um sistema operacional. Com menos sucesso, elas tambm usam bibliotecas de rotinas para especificar construes de controles interessantes como co-rotinas e rotinas de fechamento. Ao mesmo tempo, suas abstraes ficam num nvel suficientemente alto que, com cuidado, pode alcanar portabilidade entre mquinas. BCPL, B e C, diferem sintaticamente em muitos detalhes, mas globalmente elas so similares. Um programa consiste de declaraes globais e declaraes de funes (procedimento). Procedimentos podem ser aninhados em BCPL, mas no podem referirse a objetos no estticos definidos contendo procedimentos. B e C evitam esta restrio impondo uma mais severa ainda: nenhum procedimento aninhado. Cada uma das linguagens (exceto as primeiras verses da B) reconhece compilao separada, fornecendo meios para incluso de texto a partir de nomes de arquivos. Vrios mecanismos sintticos e lxicos da BCPL so mais elegantes e regulares do que aqueles de B e C. Por exemplo, procedimentos em BCPL e declaraes de dados tm uma estrutura mais uniforme, e ela fornece um conjunto de construes de loop mais completo. Embora programas em BCPL sejam notacionalmente fornecidos a partir de um fluxo indelimitado de caracteres, regras inteligentes permitem colocar ponto-e-vrgula aps sentenas que terminam no limite de uma linha. B e C omitem esta convenincia e terminam a maioria das sentenas com ponto-e-vrgula. Apesar das diferenas, a maioria das sentenas e operadores em BCPL projeta-se diretamente nas declaraes em B e C. Algumas das diferenas estruturais entre BCPL e B originam-se de limitaes na memria intermediria. Por exemplo, declaraes BCPL podem tomar esta forma: let P1 be command and P2 be command and P3 be command ... onde o texto do programa representado por command contm procedimentos inteiros. As subdeclaraes conectadas por um and ocorrem simultaneamente, assim o nome P3 conhecido dentro do procedimento P1. Similarmente, BCPL pode empacotar um grupo de declaraes e sentenas em uma expresso que produzem um valor, por exemplo: E1 := valof $( declarations ; commands ; resultis E2 $) + 1 O compilador BCPL manipulou prontamente tais construes armazenando e avaliando uma representao gramaticalmente analisada do programa inteiro antes de produzir a sada. Limitaes de armazenamento no compilador B exigiram uma tcnica de passo nico na qual a sada era gerada o mais rpido possvel, e o reprojeto sinttico elaborado foi levado adiante na linguagem C. Certos aspectos menos agradveis da BCPL so devidos a seus prprios problemas tecnolgicos e foram conscientemente evitados no projeto da B. Por exemplo, a BCPL usa um mecanismo de 'vetor global' para comunicar-se entre programas compilados separadamente. Neste esquema, o programador associa explicitamente o nome de cada procedimento externo visvel e objeto de dados com um offset numrico em um vetor global; a linkagem era realizada no cdigo compilado usando estes offsets numricos. A linguagem B livrou-se desta inconvenincia insistindo inicialmente que o programa inteiro seria apresentado todo de uma vez ao compilador. Implementaes posteriores da B, e todas aquelas da C, usam um linker convencional para resolver nomes externos que aparecem em arquivos compilados separadamente, ao invs de colocar o fardo de assinalar offsets ao programador.

Outras mudanas foram introduzidas na transio da BCPL para a B como um tpico experimental, sendo que algumas permanecem controversas, por exemplo, a deciso de usar um simples caracter = para assinalamento ao invs de :=. Similarmente, a B usa /* */ para encerrar comentrios, ao passo que a BCPL usa // para ignorar texto at o final da linha. O legado da PL/I evidente aqui (C++ ressuscitou a conveno de comentrio da BCPL). A linguagem Fortran influenciou a sintaxe das declaraes: declaraes em B comeam com um especificador como auto ou static, seguidas por uma lista de nomes. A linguagem C no somente seguiu este estilo, mas o ornamentou colocando suas palavras-chave especificadoras de tipo no incio das declaraes. Nem toda a diferena entre a linguagem BCPL documentada no livro de Richards [Richards 79] e a linguagem B era deliberada; ns comeamos de uma verso inicial da BCPL [Richards 67]. Por exemplo, o endcase que termina uma declarao switchon em BCPL no estava presente na linguagem quando ns a aprendemos nos anos 60. Assim a sobrecarga da palavra-chave break, usada para sair de uma declarao switch da B e C, deve-se a uma evoluo divergente ao invs de uma mudana consciente. Em contraste com a variao de sintaxe que ocorreu durante a criao da linguagem B, o ncleo do contedo semntico da BCLP - seu modelo estruturado e regras de avaliao de expresses - permaneceu intacto. Ambas as linguagens no possuam tipos, ou melhor, tinham um simples tipo de dado, o 'word' ou 'cell', um padro de bit de comprimento fixo. A memria nestas linguagens consiste de um array linear de tais clulas, sendo que o significado do contedo de uma clula depende da operao aplicada. O operador +, por exemplo, simplesmente adiciona seus operandos usando a instruo de adio de inteiros da mquina. As outras operaes so igualmente inconscientes do significado atual de seus operandos. Pelo fato da memria ser um array linear, era possvel interpretar o valor em uma clula como um ndice neste array, sendo que a BCPL supre um operador para este propsito. Na linguagem original ele era rv, passando depois a ser !, enquanto que a B usa o unrio *. Assim, se p uma clula contendo o ndice (ou endereo de, ou ponteiro para) de outra clula, *p refere-se ao contedo do ponteiro para a clula, ou como um valor em uma expresso ou como um alvo de uma atribuio. Pelo fato dos ponteiros em BCPL e B serem meramente ndices inteiros na memria, a aritmtica neles significativa: se p o endereo de uma clula, ento p + 1 o endereo da prxima clula. Esta conveno o bsico para a semntica de arrays em ambas as linguagens. Quando em BCPL uma pessoa escreve let V = vec 10 ou em B, auto V[10]; o efeito o mesmo: a clula nomeada V alocada, ento outro grupo de 10 clulas contnuas so colocadas ao lado e o ndice da memria da primeira delas colocada em V. Por uma regra geral, em B a expresso *(V+i) adiciona V e i, referindo-se a i-sima localizao aps V. Ambas, BCPL e B, adicionaram notaes especiais para suavizar tais acessos a array; em B uma expresso equivalente : V[i] e em BCPL V!i

Esta aproximao com arrays era incomum naquela ocasio; a linguagem C assimilaria isto depois de modo at menos convencional. As linguagens BCPL, B e C, no suportam fortemente dados caracter; cada uma trata strings como vetores de inteiros e suplementam regras gerais com algumas poucas convenes. Nas linguagens BCPL e B, uma string literal denota o endereo de uma rea esttica inicializada com caracteres da string, armazenados em clulas. Em BCPL, o primeiro byte armazenado contm o nmero de caracteres na string; em B, no h contador e strings so terminados por um caracter especial, o caracter '*e'. Esta mudana foi feita parcialmente para evitar a limitao do comprimento de uma string causada pela reteno do contador em um espao de 8 ou 9 bits e em parte porque, em nossa experincia, manter o contador parecia ser menos conveniente do que usar um terminador. Caracteres individuais numa string em BCPL eram usualmente manipulados distribuindo a string em outro array, um caracter por clula, juntando-os depois; a B fornecia rotinas correspondentes, mas as pessoas usaram mais freqentemente outras funes de biblioteca que acessavam ou substituam caracteres individuais em uma string.

Mais Histria
Aps a verso TGM da B estar trabalhando, Thompson reescreveu a B em si mesma (um passo de bootstrapping). Durante o desenvolvimento, ele lutou continuamente contra limitaes de memria: cada adio linguagem inchava o compilador de modo que dificilmente poderia ajustar-se, mas cada reescrita tomava vantagem da caracterstica reduzida de seu tamanho. Por exemplo, a B introduziu operadores de atribuio generalizados, usando x=+y para adicionar y a x. A notao veio da Algol 68 [Wijngaarden 75] via Mcllroy, que a tinha incorporado em sua verso da TGM. (Na B e na primitiva C, o operador era =+ ao invs de +=; este erro, reparado em 1976, foi induzido pelo modo fcil e sedutor de manipulao da primeira forma no analisador lxico da B.) Thompson foi um passo adiante inventando os operadores ++ e --, os quais incrementam ou decrementam; sua posio pr-fixada ou ps-fixada determina se a alterao acontece antes ou depois de se observar o valor do operando. Eles no estavam nas primeiras verses da B, mas apareceram ao longo do caminho. As pessoas freqentemente supem que eles foram criados para usar os modos de auto-incremento e autodecremento de endereo do DEC PDP-11 na qual a C e o Unix tornaram-se populares. Esta uma impossibilidade histrica, visto que no havia PDP-11 quando a B foi desenvolvida. O PDP-7, contudo, tinha umas poucas clulas de memria de autoincremento, com a propriedade que uma referncia indireta memria por feita por meio delas incrementava a clula. Esta caracterstica provavelmente sugeriu tais operaes a Thompson; a generalizao para as tornar ps ou pr-fixadas era prprio dele. Na verdade as clulas de auto-incremento no eram usadas diretamente na implementao dos operadores, e uma motivao forte para a inovao era provavelmente a observao por parte dele que a traduo de ++x era menor do que x=x+1. O compilador B no PDP-7 no gerou instrues de mquina, mas ao invs disso threaded code' [Bell 72], um esquema interpretativo na qual a sada do compilador consistia de uma seqncia de endereos de fragmentos de cdigo que executavam as operaes elementares. As operaes tpicas, especialmente em B, agiam em uma simples pilha de mquina. No sistema Unix PDP-7, somente poucas coisas foram escrita em B, exceto a prpria B, isto porque a mquina era muito pequena e lenta para algo mais do que experimentos;

reescrever completamente o sistema operacional e os utilitrios em B era um passo muito caro para parecer possvel. Em algum ponto Thompson aliviou o espao de endereamento oferecendo um compilador B virtual que permitia ao programa interpretado ocupar mais do que 8K bytes atravs da paginao do cdigo e dados dentro do interpretador, mas era muito lento para ser prtico para as utilidades comuns. Apesar disso, alguns utilitrios escritos em B apareceram, incluindo uma verso primitiva da calculadora de preciso varivel dc, familiar aos usurios Unix [Mcllroy 79]. A mais ambiciosa iniciativa que eu empreendi foi um genuno compilador-cruzado que traduzia as instrues B para instrues da mquina GE-635, mas no em threaded code. Ele era uma pequena excurso de fora: um completo compilador B, escrito em sua prpria linguagem e gerando cdigo para um Mainframe de 36-bit que rodava em uma mquina de 18-bit com 4K palavras de espao de endereamento para usurio. Este projeto foi possvel somente por causa da simplicidade da linguagem B e seu sistema de run-time. Embora ns ocasionalmente nos entretivssemos pensando sobre a implementao de uma das linguagens daquele tempo como Fortran, PL/I ou Algol 68, tal projeto parecia desesperadamente grande para nossos recursos: muitas ferramentas simples e pequenas foram requeridas. Todas aquelas linguagens influenciaram nosso trabalho, mas era mais divertido fazer as coisas de nosso prprio jeito. Por volta de 1970, o projeto Unix tinha mostrado-se suficientemente promissor para que ns adquirssemos o novo DEC PDP-11. O processador estava entre os primeiros de sua linha a ser entregues pela DEC, e passaram-se trs meses antes que o seu disco chegasse. Fazer programas em B rodar nele usando a tcnica threaded requeria somente escrever os fragmentos de cdigo para os operadores e um simples assembler que eu escrevi em B; logo, o dc tornou-se o primeiro programa interessante a ser testado, antes de qualquer sistema operacional, em nosso PDP-11. Quase como que rapidamente, ainda esperando pelo disco, Thompson recodificou o kernel do Unix e alguns comandos bsicos na linguagem de montagem do PDP-11. Dos 24K bytes de memria na mquina, o primitivo sistema Unix PDP-11 usava 12K bytes para o sistema operacional, um minsculo espao para programas do usurio e restante como RAM disk. Esta verso foi somente para testes, no para trabalho real. Uma vez que seu disco apareceu, ns rapidamente migramos para ele aps transliterar comandos da linguagem de montagem para o dialeto do PDP-11 e portando aqueles j escritos em B. Por volta de 1971, nosso pequeno centro de computao estava comeando a ter usurios. Todos ns queramos criar softwares interessantes mais facilmente. Usar o montador era mais enfadonho do que usar B, e apesar de seus problemas de desempenho, tinha sido completada uma pequena biblioteca de rotinas de servios teis que estava sendo usada para programas mais novos. Entre os resultados mais notveis deste perodo estava a primeira verso de Steve Johnson do yacc parser-generator [Johnson 79a].

Os problemas da B
As mquinas nas quais ns primeiramente usamos a BCPL, e depois a B, eram endereadas por palavra, e nestas linguagens o simples tipo de dado, o cell, equiparavase com a palavra de hardware da mquina. O advento do PDP-11 exps vrias insuficincias do modelo semntico da B. Primeiro, seus mecanismos de manipulao de caracter, herdados com poucas mudanas da BCPL, eram desajeitados: usar bibliotecas de procedimentos para distribuir strings em clulas individuais e depois uni-las, ou ter acesso e substituir caracteres individuais, comeou a parecer desajeitado, at mesmo tolo, em uma mquina orientada para byte.

Segundo, embora o PDP-11 original no fornecesse aritmtica de ponto flutuante, o fabricante prometeu que ela logo estaria disponvel. Operaes de ponto flutuante tinham sido adicionadas a BCPL em nossos compiladores Multics e GCOS atravs da definio de operadores especiais, mas o mecanismo s era possvel por que nas referidas mquinas uma simples palavra era grande o bastante para conter um nmero em ponto flutuante; isto no era verdadeiro nos 16-bits do PDP-11. Finalmente, o modelo da B e da BCPL implicaram em overhead no tratamento com ponteiros: as regras da linguagem, definindo um ponteiro como um ndice em um array de palavras, forava os ponteiros a ser representados como palavras ndices. Cada referncia a ponteiro gerava uma converso de escala em tempo de execuo do ponteiro para o endereo do byte esperado pelo hardware. Por todas estas razes, parecia que um esquema de tipagem era necessrio para lidar com caracteres, endereamento de byte e preparar-se para o hardware de pontoflutuante. Outros assuntos, particularmente segurana de tipo e checagem de interface, no pareciam ser importantes como se tornaram depois. Aparte os problemas com a prpria linguagem, a tcnica threaded-code do compilador B rendeu programas mais lentos que os seus contrapartes em linguagem de montagem, de modo que ns descartamos a possibilidade de recodificar o sistema operacional ou seus utilitrios centrais em B. Em 1971 eu comecei a estender a linguagem B adicionando um tipo caracter e tambm reescrevendo seu compilador para gerar instrues de mquina do PDP-11 ao invs de threaded code. Assim a transio da B para a C foi contempornea com a criao de um compilador capaz de produzir programas rpidos e pequenos o bastante para competir com a linguagem assembler. Eu chamei o idioma ligeiramente estendido de NB (New B).

C embrionrio
A NB teve uma existncia to breve que nenhuma descrio completa dela foi escrita. Ela fornecia os tipos int, char, arrays (para os tipos int e char) e ponteiros para eles, declarados num estilo simbolizado por int i, j; char c, d; int iarray[10]; int ipointer[ ]; char carray[10]; char cpointer[ ]; A semntica de arrays permaneceu exatamente como em B e BCPL: as declaraes de iarray e carray criam clulas inicializadas dinamicamente com um valor apontando para o primeiro de uma seqncia de 10 inteiros e caracteres respectivamente. As declaraes para ipointer e cpointer omitem o tamanho, asseverando que nenhum armazenamento deve ser alocado dinamicamente. Dentro de procedimentos, a interpretao de ponteiros por parte das linguagens era idntica a de variveis arrays: uma declarao de ponteiro criava uma clula, diferindo de uma declarao de um array somente pelo fato do programador estar esperando assinalar uma referncia ao invs de deixar o compilador alocar espao e inicializar a clula.

Valores armazenados em clulas demarcadas para arrays e ponteiros eram endereos de mquina, medidos em bytes, da correspondente rea de armazenamento. Portanto, a indireo atravs de ponteiro no implicava em overhead em tempo de execuo para escalar o ponteiro da palavra para o byte offset. Por outro lado, o cdigo de mquina para subscrio de arrays e aritmtica de ponteiros depende agora do tipo do array ou do ponteiro: computar iarray[i] ou ipointer+i implicou escalar i pelo tamanho do objeto referenciado. Estas semnticas representaram uma fcil transio da B e eu as experimentei por alguns meses. Problemas ficaram evidentes quando eu tentei estender a notao de tipo, especialmente para adicionar tipos estruturados (record). Estruturas, parecia, deveriam mapear de modo intuitivo na memria da mquina, mas em uma estrutura contendo um array, no havia um bom lugar para esconder o ponteiro contendo a base do array, nem qualquer modo conveniente para arranjar que ele seja inicializado. Por exemplo, o diretrio de entradas dos primeiros sistemas Unix poderia ser escrito em C como struct { int inumber; char name[14]; }; Eu no somente queria a estrutura para caracterizar um objeto abstrato, mas tambm para descrever uma coleo de bits que poderiam ser lidos de um diretrio. Aonde o compilador poderia esconder o ponteiro para nomear o que a semntica exigiu? At mesmo se estruturas fossem pensadas de modo mais abstrato e o espao para ponteiros pudesse ser escondido de alguma maneira, como eu poderia manipular o problema tcnico de inicializar corretamente estes ponteiros quando alocando um objeto complicado, talvez um que especificasse estruturas contendo arrays armazenando estruturas? A soluo constituiu o salto crucial na cadeia evolucionria entre a linguagem sem tipos BCPL e a linguagem com tipos C. Ela eliminou a materializao do ponteiro em armazenamento e, ao invs disso, causou a criao do ponteiro quando o array mencionado em uma expresso. A regra, que sobrevive na C de hoje, que valores de um tipo array so convertidos, quando eles aparecem em expresses, em ponteiros para o primeiro dos objetos que compem o array. Esta inveno permitiu que a maioria do cdigo existente em B continuasse a trabalhar, apesar da troca subjacente na semntica da linguagem. Os poucos programas que assinalavam novos valores para um array para ajusta-los sua origem possivelmente em B e BCPL, sem sentido em C foram facilmente reparados. Mais importante, a nova linguagem reteve uma coerente e vivel (se no incomum) explicao da semntica de arrays, enquanto abriu o caminho para um tipo de estrutura mais abrangente. A segunda inovao que distingue mais claramente a C de suas predecessoras este tipo de estrutura e especialmente sua expresso na sintaxe de declaraes. A NB oferecia os tipos bsicos int e char, juntos com arrays deles e ponteiros para eles, mas nenhum modo de composio adicional. A generalizao foi requerida: dado um objeto para qualquer tipo, deveria ser possvel descrever um novo objeto que junta vrios em um array, obtidos de uma funo, ou sendo um ponteiro para ele. Para cada objeto de tal tipo composto j havia um modo para mencionar o objeto subjacente: indexar o array, chamar a funo, usar o operador de indireo no ponteiro. O

raciocnio analgico levou a uma sintaxe de declarao para nomes que reflete isso na sintaxe de expresso na qual os nomes aparecem tipicamente. Assim, int i, *pi, **ppi; declara um inteiro, um ponteiro para um inteiro e um ponteiro para um ponteiro que aponta para um inteiro. A sintaxe dessas declaraes reflete a observao de que i, *pi e **ppi todos provm um tipo int quando usados em uma expresso. Similarmente, int f(), *f(), (*f)(); declara uma funo retornando um inteiro, uma funo retornando um ponteiro para um inteiro, um ponteiro para uma funo retornando um inteiro; int *api[10], (*pai)[10]; declaram um array de ponteiros para inteiros e um ponteiro para um array de inteiros. Em todos estes casos a declarao de uma varivel semelhante a seu uso em uma expresso cujo tipo um dos especificados no cabealho da declarao. O esquema do tipo de composio adotado pela C deve considervel dbito ao Algol 68, embora no o faa, talvez, emergir na forma que os partidrios da Algol aprovariam. A noo central que eu capturei da Algol foi um tipo estruturado baseado em tipos atmicos (incluindo estruturas), compostas em arrays, ponteiros (referncias) e funes (procedimentos). O conceito do Algol 68 de unies e moldagens tambm teve influncia que apareceu depois. Aps criar o sistema de tipos, a sintaxe associada e o compilador para a nova linguagem, eu senti que ela merecia um novo nome; NB parecia insuficientemente distintivo. Eu decidi seguir o estilo de letra nica e a chamei de C, deixando em aberto a questo se o nome representava uma progresso pelo alfabeto ou pelas letras em BCPL.

Neonatal C
Rpidas mudanas continuaram aps a linguagem ter sido nomeada, por exemplo, a introduo dos operadores && e ||. Em BCPL e B, a avaliao de expresses depende do contexto: dentro de um if e outras declaraes condicionais que comparam o valor de uma expresso com zero, estas linguagens colocam uma interpretao especial nos operadores and (&) e or (|). Em contextos ordinrios, eles operam bitwise, mas na declarao em B if (e1 & e2) ... o compilador deve avaliar e1, e se ele diferente de zero, avaliar e2, e se ele tambm diferente de zero, elaborar a declarao dependente no if. A exigncia desce recursivamente nos operadores & e | dentro de e1 e e2. O curto-circuito semntico de operadores booleanos em tal contexto de "valores verdadeiros" parecia desejvel, mas a sobrecarga dos operadores era difcil de explicar e usar. Por sugesto de Alan Snyder, eu introduzi os operadores && e || para tornar o mecanismo mais explcito. A introduo tardia explica uma infelicidade das regras de precedncia da C. Em B uma pessoa escreve if (a==b & c) ... para checar se a igual a b e se c diferente de zero; em tal expresso condicional melhor que o & tenha precedncia menor do que ==. Na converso da B para a C, a pessoa necessita trocar o & por &&; para tornar a converso menos dolorosa, ns decidimos manter a precedncia do operador & a mesma do operador ==, e meramente

separar a precedncia do && ligeiramente do &. Hoje, parece que teria sido prefervel mover a relativa precedncia do & e do ==, simplificando assim um acontecimento comum na linguagem C: para testar um valor mascarado contra outro valor, algum escreveria if ((a&mask) == b) ... aonde os parntesis internos so requeridos, mas facilmente esquecidos. Muitas outras mudanas ocorreram por volta de 1972-1973, mas o mais importante foi introduo do pr-processador, em parte no urgir de Alan Snyder [Snyder 74], mas tambm em reconhecimento da utilidade do mecanismo de incluso de arquivos disponveis em BCPL e PL/I. Sua verso original era extremamente simples e fornecia somente incluso de arquivos e simples substituio de strings: #include e #define (de macros sem parmetros). Logo depois, ele foi estendido, principalmente por Mike Lesk e ento por John Reiser, incorporando macros com argumentos e compilao condicional. O pr-processador foi considerado originalmente um suplemento opcional da linguagem. De fato, por alguns anos, ele nem mesmo invocou que o programa contivesse ao menos um sinal especial no seu incio. Esta atitude persistiu e explica a incompleta integrao da linguagem do pr-processador com o resto da linguagem e a impreciso de sua descrio nos primeiros manuais de referncia.

Portabilidade
No incio de 1973, o essencial da moderna linguagem foi completado. A linguagem e o compilador eram fortes o bastante para nos permitir reescrever o kernel do Unix para o PDP-11 durante o vero daquele ano. (Thompson tinha feito uma breve tentativa de produzir um sistema codificado em uma verso primitiva da C antes das estruturas em 1972, mas deixou o esforo). Tambm durante este perodo, o compilador foi transportado para outras mquinas prximas, particularmente o Honeywell 635 e IBM 360/370; pelo fato da linguagem no poder viver em isolamento, os prottipos para as modernas bibliotecas foram desenvolvidos. Em particular, Lesk escreveu um portvel pacote de I/O [Lesk 72] que foi refeito para tornar-se as rotinas de I/O padro da C. Em 1978 Brian Kernighan e eu publicamos A Linguagem de Programao C [Kernighan 78]. Embora no descrevendo algumas adies que logo ficaram comuns, este livro serviu como a referncia da linguagem at um padro formal ser adotado mais de dez anos depois. Embora ns trabalhssemos prximos neste livro, havia uma clara diviso de trabalho: Kernighan escreveu quase todo o material expositrio, enquanto eu fui responsvel pelo apndice contendo o manual de referncia e o captulo sobre interfaceamento com o sistema Unix. Durante 1973-1980, a linguagem cresceu um pouco: o tipo estruturado ganhou unsigned (sem sinal), long (longo), union (unio) e enumeration types (tipos enumerados), e as estruturas tornaram-se quase objetos de primeira classe (faltando somente uma notao para literais). Desenvolvimentos igualmente importantes apareceram em seu ambiente e acompanharam a tecnologia. Escrever o kernel do Unix em C tinha dado a ns bastante confiana na eficincia e utilidade da linguagem, de modo que ns comeamos a recodificar os utilitrios do sistema e ferramentas, movendo ento os mais interessantes deles para outras plataformas. Como descrito em [Johnson 78a], ns descobrimos que o mais duros problemas em propagar ferramentas Unix no eram a interao da linguagem C com novo hardware, mas na adaptao do software existente de outros sistemas operacionais. Assim Steve Johnson comeou a trabalhar no pcc, um compilador C que intentava ser fcil de ser transportado para novas mquinas [Johnson 78b], enquanto ele, Thompson e eu comeamos a mover os sistema Unix propriamente dito para o computador Interdata 8/32.

A linguagem mudou durante este perodo, especialmente por volta de 1977, quando era largamente enfocada a considerao de portabilidade e de segurana de tipo, em um esforo para enfrentar os problemas que ns previmos e observamos ao mover um considervel corpo de cdigo para a nova plataforma Interdata. A C naquele momento ainda manifestou sinais fortes de sua origem sem tipos. Ponteiros, por exemplo, eram pouco distintos dos ndices integrais de memria nos primeiros manuais da linguagem ou no cdigo existente; a similaridade das propriedades aritmticas de ponteiros de caracteres e inteiros no assinalados tornou difcil a tentao de os identificar. Os tipos unsigned foram adotados para tornar a aritmtica de no assinalados disponvel sem confuso com a manipulao de ponteiros. Semelhantemente, a primitiva linguagem tolerou a assinalao entre inteiros e ponteiros, mas esta prtica comeou a ser desencorajada; uma notao para converses de tipo (chamada de casts (moldagens) do exemplo da Algol 68) foi inventada para especificar converses de tipo mais explicitamente. Iludida pelo exemplo da PL/I, a primitiva C no amarrou firmemente a estrutura de ponteiros para as estruturas que eles apontavam, permitindo que programadores escrevessem ponteiro membro quase sem levar em conta o tipo de ponteiro; tal expresso foi levada sem crticas como uma referncia para uma regio de memria designada pelo ponteiro, enquanto o membro especificava somente um offset e um tipo. Embora a primeira edio de K&R descrevesse a maioria das regras que anteciparam o tipo de estrutura da C para a sua presente forma, muitos programas escritos no estilo mais antigo, mais relaxado, persistiram, fazendo assim com que muitos compiladores tolerassem isto. Para encorajar as pessoas a prestar mais ateno nas regras oficiais da linguagem, detectar construes legais, mas suspeitas, e ajudar a achar erros de comparao de interface indetectveis com simples mecanismos para separar compilao, Steve Johnson adaptou seu compilador pcc para produzir lint [Johnson 79b], o qual esquadrinhava um conjunto de arquivos e comentava construes duvidosas.

Crescimento no Uso
O sucesso de nosso experimento de portabilidade no Interdata 8/32 conduziu a outro experimento por Tom London e John Reiser no DEC VAX 11/780. Esta mquina tornou-se muito mais popular do que o Interdata, e o Unix e a linguagem C espalharam-se rapidamente, dentro e fora da AT&T. Embora na metade dos anos 70 o Unix estivesse em uso por uma variedade de projetos dentro do sistema Bell, bem como por um pequeno grupo de organizaes industriais, acadmicas e governamentais fora de nossa companhia, seu crescimento real veio somente aps a portabilidade ter sido alcanada. Particularmente de nota foram as verses System III e System V do sistema da emergente diviso de sistemas de computadores da AT&T, baseado no trabalho de desenvolvimento da companhia e grupos de pesquisa, e a srie de lanamentos BSD pela Universidade da Califrnia em Berkeley que derivaram de organizaes de pesquisa no Bell Laboratories. Durante os anos 80 o uso da linguagem C espalhou-se globalmente e compiladores tornaram-se disponveis em quase todas as arquiteturas de mquinas e sistemas operacionais; em particular ela tornou-se popular como uma ferramenta de programao para computadores pessoais, para fabricantes de software comercial destas mquinas e usurios finais interessados em programao. No comeo da dcada, todo compilador era baseado no pcc de Johnson; por volta de 1985 havia muitos produtores independentes de compiladores.

Padronizao
Por volta de 1982 estava claro que a C necessitava de uma padronizao formal. A melhor aproximao para um padro, a primeira edio de K&R, j no descrevia a linguagem em uso atual; em particular, no mencionava os tipos void e enum. Enquanto pressagiou a mais nova aproximao para estruturas, somente depois dela ter sido publicada que a linguagem suportou design-las, passando-as para funes e recebendo-as de funes, associando os nomes dos membros firmemente com a estrutura ou unio que os continha. Embora a maioria dos compiladores distribudos pela AT&T incorporassem essas mudanas e a maioria dos fornecedores de compiladores no baseados no pcc rapidamente as incorporassem, ela permaneceu incompleta. A primeira edio K&R tambm era insuficientemente precisa em muitos detalhes da linguagem e tornou-se crescentemente impraticvel considerar o pcc como um compilador de referncia; ele no encarnou igualmente a linguagem descrita por K&R, deixando extenses subseqentes sozinhas. Finalmente, o uso incipiente da C em projetos sujeitos a contrato comercial e governamental significou que um padro oficial era importante. Assim (no mpeto de M. D. Macllroy), a ANSI estabeleceu no vero de 1983 o comit X3J11 sob a direo do CBEMA, objetivando produzir um padro para a linguagem C. O comit X3J11 produziu seu relatrio [ANSI 89] no final de 1989, e subseqentemente este padro foi aceito pela ISO como ISO/IEC 9899-1990. Desde o princpio, o comit X3J11 tomou uma viso cautelosa, uma viso conservadora das extenses da linguagem. Para minha satisfao, eles levaram o objetivo deles a srio: desenvolver um limpo, consistente e no ambguo padro para a linguagem de programao C que codifica a definio comum existente da C e que promove a portabilidade de programas do usurio atravs de ambientes da linguagem C [ANSI 89]. O comit percebeu que a mera promulgao de um padro no faz uma mudana mundial. O comit X3J11 introduziu somente uma mudana genuinamente importante linguagem propriamente dita: ele incorporou os tipos de argumentos formais na assinatura de tipo de uma funo, usando a sintaxe emprestada da C++ [Stroustrup 86]. No estilo antigo, funes externas eram declaradas assim: double sin(); a qual diz somente que sin uma funo retornando um valor double (isto , um ponto flutuante de dupla preciso). No novo estilo, isto se tornaria double sin(double); para tornar o tipo de argumento explcito e assim encorajar uma melhor conferncia de tipo e converso apropriada. Igualmente esta adio, apesar de produzir uma linguagem notadamente melhor, causou dificuldades. O comit justificadamente sentiu que simplesmente proscrever definies de funo no estilo antigo e declaraes no era possvel, contudo tambm concordou que as novas formas eram melhores. O compromisso inevitvel era to bom quanto poderia ter sido, entretanto a definio da linguagem complicada, permitindo ambas as formas, no devendo os escritores de software porttil combater com compiladores criados fora do padro. O comit X3J11 tambm introduziu um grande nmero de pequenas adies e ajustes, por exemplo, os qualificadores de tipo const e volatile. No obstante, o processo de padronizao no mudou o carter da linguagem. Em particular, o padro C no tentou especificar formalmente a semntica da linguagem, e assim pode haver disputa em cima de pontos delicados; no obstante, ela respondeu prosperamente por mudanas no uso desde a sua descrio original, sendo suficientemente precisa para embasar implementaes nela.

Assim o ncleo da linguagem C escapou quase inclume do processo de padronizao e o padro emergiu mais como uma melhor e cuidadosa codificao do que como uma nova inveno. As mais importantes mudanas aconteceram no ambiente da linguagem: o pr-processador e a biblioteca. O pr-processador executa substituio de macros usando convenes distintas do resto da linguagem. Sua interao com o compilador nunca tinha sido bem descrita, e o comit X3J11 tentou remediar a situao. O resultado notoriamente melhor do que a explanao na edio de K&R; alm de ser mais compreensiva, ela fornece operaes, como concatenao de smbolos, previamente disponveis somente por acidentes de implementao. O comit X3J11 acreditou que uma completa e cuidadosa descrio de um padro para a biblioteca C era to importante quanto seu trabalho na linguagem propriamente dita. A prpria linguagem C no fornece entrada-sada ou qualquer outra interao com o mundo externo, e assim depende de um conjunto de procedures padro. Por momento da publicao da K&R, a linguagem C era pensada principalmente como a linguagem de programao do Unix; embora ns fornecssemos exemplos da biblioteca de rotinas intentando as transpor para outros sistemas operacionais, o apoio subjacente do Unix era entendido implicitamente. Assim, o comit X3J11 gastou muito de seu tempo projetando e documentando um conjunto de rotinas de biblioteca requeridas para serem disponveis em todas implementaes conforme o padro. Pelas regras do processo de padronizao, a atividade corrente do comit X3J11 limitada a emitir interpretaes sobre o padro existente. Contudo, um grupo informal originalmente citado por Rex Jaeschke como NCEG (Numerical C Extensions Group) tem sido oficialmente aceito como subgrupo X3J11.1, e eles continuaram a considerar extenses para a C. Como o nome indica, muitas daquelas possveis extenses so intentadas para tornar a linguagem mais satisfatria para uso numrico: por exemplo, arrays multidimensionais que so determinados dinamicamente, incorporao de facilidades de procedimentos com a aritmtica IEEE e tornando a linguagem mais efetiva em mquinas com vetor ou outras caractersticas de arquitetura avanadas. Nem todas as extenses so especificadamente numricas; elas incluem a notao para literais de estruturas.

Sucessores
As linguagens B e C tem vrios descendentes diretos, entretanto elas no rivalizam com Pascal na gerao de descendncia. Uma filial lateral desenvolveu-se cedo. Quando Steve Johnson visitou a Universidade de Waterloo em 1972, ele trouxe a B com ele. L ela tornou-se popular em mquinas Honeywell e depois gerou Eh e Zed (a resposta canadense para "o que segue B?"). Quando Johnson retornou ao Bell Labs em 1973, ele estava desconcertado por achar que a linguagem que ele mesmo tinha semeado no Canad tinha evoludo ao voltar para casa; at mesmo seu programa yacc tinha sido reescrito em C por Aland Snyder. Os mais recentes descendentes da C formal incluem Concurrent C [Gehani 89], Objective C [Cox 86], C* [Thinking 90] e especialmente C++ [Stroustrup 86]. A linguagem tambm usada globalmente como uma representao intermediria (essencialmente, como uma linguagem assembler porttil) para uma larga variedade de compiladores, tanto para descendentes diretos como C++ ou linguagens independentes como Modula 3 [Nelson 91] e Eiffel [Meyer 88].

Crtica

Duas idias so mais caractersticas da C entre linguagens de sua classe: o relacionamento entre arrays e ponteiros e o modo pela qual a sintaxe de declarao imita sintaxe de expresso. Eles tambm esto entre as mais freqentemente caractersticas criticadas e freqentemente servem como blocos de tropeo para iniciantes. Em ambos os casos, acidentes histricos ou erros tem exarcebado sua dificuldade. A mais importante destas tem sido a tolerncia de compiladores C para erros em tipo. Como deveria estar claro pela a histria acima, a C evoluiu de linguagens sem tipos. Ela no apareceu de repente para seus usurios e desenvolvedores como uma nova linguagem com suas prprias regras; ao invs disso ns tivemos que adaptar programas existentes conforme o desenvolvimento da linguagem e dar desconto para um corpo de cdigo existente. (Depois, o comit ANSI X3J11 que a padronizou enfrentaria o mesmo problema.) Compiladores em 1977, e igualmente bem aps, no reclamaram sobre usos tais como assinalamento entre inteiros e ponteiros ou uso de objetos de um tipo errado para referirse a membros de estruturas. Embora a definio da linguagem apresentada na primeira edio de K&R fosse razoavelmente (entretanto no completamente) coerente em seu tratamento de regras de tipo, este livro admitiu que compiladores existentes no deveriam for-los. Alm disso, algumas regras projetadas para facilitar primitivas transies contriburam para posterior confuso. Por exemplo, os colchetes vazios na declarao de funo int f(a) int a[ ]; { ... } um fssil vivo, um remanescente do modo da NB de declarar um ponteiro; a , neste caso especial, interpretado em C como um ponteiro. A notao sobreviveu em parte por causa da compatibilidade, em parte sob a racionalizao que permitiria a programadores comunicar aos leitores o intento de passar f, um ponteiro gerado de um array, em lugar de uma referncia a um simples inteiro. Infelizmente, ela serve para muito atrapalhar o estudante em como alertar o leitor. Em C K&R, o fornecimento de argumentos de um tipo formal para uma chamada de funo era de responsabilidade do programador, e os compiladores existentes no checavam o tipo. A falha da linguagem original em incluir tipos de argumentos na assinatura de uma funo foi uma fraqueza significante, e foi realmente a nica que requereu do comit X3J11 a mais corajosa e dolorosa inovao. O projeto inicial explicado (se no justificado) por minha vacncia de problemas tecnolgicos, especialmente checagem cruzada entre arquivos fonte compilados separadamente e minha incompleta assinalao das implicaes de mudana entre uma linguagem sem tipos para uma com tipos. O programa lint, mencionado acima, tentou aliviar o problema: entre suas outras funes, lint checava a consistncia e coerncia de um programa inteiro esquadrinhando um conjunto de arquivos fonte, comparando os tipos de argumentos de funo usados em chamadas com aqueles de suas definies. Um acidente de sintaxe contribuiu para a percebida complexidade da linguagem. O operador de indireo, representado em C por *, sintaticamente um operador prefixado unrio, exatamente como em BCPL e B. Isto trabalha bem em expresses simples, mas nos casos mais complexos, parnteses so requeridos para dirigir a anlise gramatical. Por exemplo, para distinguir a indireo pelo valor retornado por uma funo da chamada por uma funo designada por um ponteiro, algum escreveria *fp() e (*pf)() respectivamente. O estilo usado em expresses transporta-se para declaraes, assim os nomes poderiam ser declarados int *fp(); int (*pf)(); Em formato mais ornamentado, mas ainda em casos realsticos, as coisas ficam piores:

int *(*pfp)(); um ponteiro para um inteiro retornando um ponteiro para um inteiro. H dois efeitos ocorrendo. Mais importante, C tem um conjunto relativamente rico de modos de descrever tipos (comparados, digamos, com Pascal). Declaraes em linguagens to expressivas quanto C, Algol 68, por exemplo, descrevem objetos igualmente duros de entender, simplesmente porque os objetos so eles mesmos complexos. Um segundo efeito devese a detalhes de sintaxe. Declaraes em C devem ser lidas em um estilo de "dentro para fora" que muitos tem achado difcil de compreender [Anderson 80]. Sethi [Sethi 80] observou que muitas das declaraes aninhadas e expresses se tornariam simples se o operador de indireo tivesse sido tomado como ps-fixado ao invs de pr-fixado, mas ento era muito tarde para mudar. Apesar de suas dificuldades, eu acredito que a aproximao de declaraes da C permanece plausvel, e eu estou vontade com isto; ela um princpio de unificao til. A outra caracterstica da C, seu tratamento de arrays, mais suspeita em fundamentos prticos, entretanto ela tem suas reais virtudes. Embora a relao entre ponteiros e arrays seja incomum, ela pode ser aprendida. Alm disso, a linguagem mostra considervel fora para descrever importantes conceitos, por exemplo, vetores cujo comprimento varivel em tempo de execuo, com somente umas poucas regras bsicas e convenes. Em particular, strings de caracteres so manipuladas pelos mesmos mecanismos como qualquer outro array, mais a conveno que um caracter nulo termina a string. interessante comparar a aproximao da C com estes vetores com duas linguagens quase contemporneas, Algol 68 e Pascal [Jensen 74]. Arrays em Algol 68 ou tem limites fixos ou so flexveis: considervel mecanismo requerido em ambos na definio da linguagem, e em compiladores, para acomodar arrays flexveis (e nem todos os compiladores os implementam completamente.) O Pascal original tinha somente arrays de tamanho fixo e strings, e isto se mostrou ser limitado [Kernighan 81]. Depois, isto foi parcialmente fixado, entretanto a linguagem resultante no universalmente disponvel. A linguagem C trata strings como arrays de caracteres convencionalmente terminados por um marcador. Aparte uma regra especial sobre inicializao atravs de literais string, a semntica de strings completamente subsomada por regras mais gerais governando todos os arrays, e como resultado a linguagem simples para descrever e para traduzir do que uma que incorpora a string como um nico tipo de dado. Alguns custos resultam desta sua aproximao: certas operaes com string so mais custosas do que outras porque o cdigo de aplicao, ou a rotina de biblioteca, deve ocasionalmente procurar pelo final de uma string, porque poucas operaes embutidas esto disponveis, e porque o fardo da administrao de armazenamento para strings cai mais pesadamente no usurio. No obstante, a aproximao para strings da C trabalha bem. Por outro lado, o tratamento de arrays da C em geral (no apenas strings) tem implicaes infortunadas para optimizao e futuras extenses. A prevalncia de ponteiros em programas C, se esses so declarados explicitamente ou surgem de arrays, significa que otimizaes devem ser cautelosas e devem usar tcnicas cuidadosas de fluxo de dados para alcanar bons resultados. Compiladores sofisticados podem entender que a maioria dos ponteiros pode possivelmente mudar, mas alguns importantes usos continuam difceis de analisar. Por exemplo, funes com argumentos ponteiro derivados de arrays so difceis de compilar em cdigo eficiente em mquinas vetor, porque raramente possvel determinar se aquele argumento ponteiro no sobrepe dados tambm referidos por outro argumento, ou so acessados externamente. Mais fundamentalmente, a definio da C especificamente descreve a semntica de arrays que mudam ou extenses que tratam arrays como objetos mais primitivos, e permitem operaes neles com um todo, tornando difcil de encaixar na linguagem existente. At

mesmo extenses para permitem a declarao e uso de arrays multidimensionais cujo tamanho determinado dinamicamente no so inteiramente diretas [MacDonald 89] [Ritchie 90], embora elas fariam a escrita de bibliotecas numricas em C mais fcil. Assim, a linguagem C cobre os mais importantes usos de strings e arrays que surgem na prtica por um uniforme e simples mecanismo, mas deixa problemas para implementaes mais altamente eficientes e para extenses. Muitas pequenas infelicidades existem na linguagem e sua descrio est alm daquelas discutidas acima, claro. H tambm crticas gerais a serem alojadas que transcendem pontos detalhados. A principal destas que a linguagem e seu ambiente fornecem pouca ajuda para a escrita de sistemas muito grandes. A estrutura de nomes fornece somente dois nveis principais, externo (visvel em qualquer lugar) e interno (dentro de um simples procedimento). Um nvel intermedirio de visibilidade (em um simples arquivo de dados e procedimentos) debilmente amarrado definio da linguagem. Assim, h pequeno suporte direto para modularizao e designers de projeto so forados a criar suas prprias convenes. Semelhantemente, a prpria C fornece duas classes de armazenamento: objetos automticos - que existem enquanto o controle reside neles ou sob um procedimento - e objetos estticos que existem ao longo da execuo de um programa. Armazenamento fora da pilha (alocao dinmica) fornecido somente por uma biblioteca de rotina e o fardo da administrao disto colocado sobre o programador: a linguagem C hostil garbage collection automtica.

De onde o sucesso?
A linguagem C um sucesso que ultrapassa de longe qualquer primitiva expectativa. Que qualidades contriburam para a difuso do seu uso? Indubitavelmente o sucesso do prprio Unix foi o mais importante fator; ele tornou a linguagem disponvel para centenas de milhares de pessoas. Reciprocamente, claro, o uso da C pelo Unix e sua conseqente portabilidade para uma grande variedade de mquina foi importante no sucesso do sistema. Mas a invaso da linguagem em outros ambientes sugere mritos mais fundamentais. Apesar de alguns aspectos misteriosos para o iniciante e ocasionalmente at mesmo para o adepto, a linguagem C permanece uma simples e pequena linguagem, traduzvel com simples e pequenos compiladores. Seus tipos e operaes so bem fundamentados naquelas fornecidas por mquinas reais, e para pessoas que usam o computador para trabalhar, aprender a linguagem para gerar programas em tempo e espao eficientes no difcil. Ao mesmo tempo a linguagem suficientemente abstrata dos detalhes da mquina de modo que a portabilidade de programa pode ser alcanada. Igualmente importante, a linguagem C e sua biblioteca central sempre permaneceram em contato com o ambiente real. Ela no foi projetada em isolamento para provar um ponto ou para servir como um exemplo, mas como uma ferramenta para escrever programas que fizeram coisas teis; ela sempre teve a inteno de interagir com um grande sistema operacional e foi considerada como uma ferramenta para construir grandes ferramentas. Uma aproximao parcimoniosa, pragmtica, influenciou as coisas que entraram na C: ela cobre as necessidades essenciais de muitos programadores, mas no tenta suprir muitas. Finalmente, apesar das mudanas que sofreu desde primeira publicao, a qual foi admitidamente informal e incompleta, a linguagem C atual como visto por milhes de usurios, usando muitos diferentes compiladores, permaneceu notavelmente estvel e unificada quando comparada quelas de similar aceitao geral, por exemplo, Pascal e

Fortran. H diferentes dialetos da C mais notrios, aqueles descritos pelo velho K&R e o novo padro C, mas na integra, a linguagem C permanece mais livre de extenses proprietrias do que outras linguagens. Talvez a mais significante extenso seja os qualificadores de ponteiros far e near intentados para lidar com as peculiaridades de alguns processadores Intel. Embora a C no fosse originalmente projetada tendo a portabilidade como uma meta principal, ela teve sucesso expressando programas, incluindo igualmente sistemas operacionais, em mquinas que variam de pequenos computadores pessoais at poderosos supercomputadores. C ardilosa, imperfeita e um enorme sucesso. Enquanto que acidentes de histria seguramente ajudaram, ela evidentemente satisfez uma necessidade por uma linguagem de implementao de sistema eficiente o bastante para descartar a linguagem assembler, contudo suficientemente abstrata e fluente para descrever algoritmos e interaes em uma larga variedade de ambientes.

Reconhecimentos
Isto sumariza compactamente os papis dos contribuintes diretos para a linguagem C de hoje. Ken Thompson criou a linguagem B em 1969-1970; ela foi derivada diretamente da BCPL de Martin Richards. Dennis Ritchie transformou a B em C durante 1971-1973, mantendo a maioria da sintaxe da B enquanto adicionava tipos e muitas outras mudanas, e escreveu o primeiro compilador para a linguagem. Ritchie, Alan Snyder, Steven C. Johnson, Michael Lesk e Thompson contriburam com idias para a linguagem durante 1972-1977, sendo que o compilador portvel de Johnson permanece amplamente usado. Durante este perodo, a coleo de rotinas cresceu consideravelmente, graas a aquelas pessoas e muitas outras no Bell Laboratories. Em 1978, Brian Kernighan e Ritchie escreveram o livro que se tornou a definio da linguagem por vrios anos. Comeando em 1983, o comit ANSI X3J11 padronizou a linguagem. Especialmente notvel em manter seus esforos na trilha foram seus funcionrios Jim Brodie, Tom Plum, P. J. Plauger e os sucessivos redatores do projeto, Lary Rosler e Dave Prosser. Eu agradeo a Brian Kernighan, Doug Mcllroy, Dave Prosser, Peter Nelson, Rob Pike, Ken Thompson e rbitros do HOPL por conselhos na preparao deste documento

Вам также может понравиться