Linguagem C: História e Padrões

- por Sergio Prado

Categorias: Linguagem C Tags: , , , ,

Em qual­quer livro de pro­gra­mação, nor­mal­mente as primeiras pági­nas são voltadas à história da lin­guagem (e são tam­bém as pági­nas que não lemos ou damos uma “pas­sada bem ráp­ida”). Mas con­hecer a origem da lin­guagem pode nos aju­dar a enten­der um pouco suas características.

C é uma lin­guagem desen­volvida por engen­heiros e para engen­heiros. Foi cri­ada em 1972 por Den­nis Ritchie para ser usada no desen­volvi­mento sis­tema opera­cional Unix no Bell Labs, que na época per­ten­cia à AT&T (hoje parte da Alcatel-Lucent). C foi derivada da lin­guagem B, desen­volvida por Ken Thomp­son, que por sua vez se baseou-se na lin­guagem BCPL.

Ritchie e Thomp­son tam­bém par­tic­i­param da equipe de desen­volvi­mento do UNIX, cujas primeiras ver­sões foram total­mente desen­volvi­das em Assem­bly. Em um certo momento, eles sen­ti­ram a neces­si­dade de uma lin­guagem mais portável para imple­men­tar o Unix no PDP-11.

Esta lin­guagem pre­cisava prover acesso de baixo nível ao hard­ware (PCU, I/Os e per­iféri­cos) e se enten­der bem com o Assem­bly, pre­cisava ser portável para que o SO pudesse rodar em difer­entes platafor­mas de hard­ware, além de ter um bom desem­penho e otimizar o uso de memória, prin­ci­pal­mente numa época em que estavam começando a sur­gir as primeiras CPUs, e o preço por byte de memória era carís­simo. Foi por­tanto destas neces­si­dades que surgiu a lin­guagem C.

Deste então, 99,99999% das arquite­turas de CPU pos­suem a imple­men­tação de um com­pi­lador C. De main­frames, super­com­puta­dores e mini­com­puta­dores, a celu­lares, reló­gios e tor­radeiras. É difí­cil encon­trar uma plataforma de hard­ware sem um com­pi­lador C com­patível.

O PRIMEIRO PADRÃO

O livro “The C Pro­gram­ming Lan­guage”, pub­li­cado em 1978 por Brian Kernighan e Den­nis Ritchie, foi con­sid­er­ado o padrão de facto da lin­guagem C durante muitos anos, até sair o padrão ANSI C. Este padrão infor­mal tam­bém ficou con­hecido como “K&R C”.

É provavel­mente o livro de C que mais se vendeu até hoje, por vários motivos. Den­tre eles, foi o primeiro livro de C disponível de forma mais abrangente, um dos autores do livro é o próprio cri­ador da lin­guagem, é escrito de forma clara e pos­sui pou­cas pági­nas, com­parado à out­ras “bíblias” que vemos por aí. Todo desen­volve­dor C dev­e­ria ter sua cópia.

A segunda edição do livro foi lançada em 1988 e atu­al­izada para ficar de acordo com o padrão ANSI C.

OS PADRÕES ANSI C E ISO C

Durante a década de 80 “choveram” imple­men­tações de com­pi­ladores C, já que naquela época a semân­tica da lin­guagem estava aberta à inter­pre­tações. Surgiu então a neces­si­dade de um padrão for­mal da lin­guagem.

Este padrão foi desen­volvido pelo ANSI (Amer­i­can National Stan­dards Insti­tute), que for­mou um comitê e rat­i­fi­cou o padrão em 1989 como ANSI X3.159‑1989 “Pro­gram­ming Lan­guage C”, tam­bém con­hecido com ANSI C ou C89.

Um ano depois o padrão foi ado­tado pela ISO (Inter­na­tional Orga­ni­za­tion for Stan­dard­iza­tion) como ISO/IEC 9899:1990, tam­bém chamado de C90. Na prática, C89 (ANSI C) e C90 (ISO C) referem-se ao mesmo padrão.

A par­tir de 1990, a ISO ficou respon­sável pela evolução do padrão. O endereço ofi­cial do grupo é este aqui, e um draft do padrão pode ser visto aqui.

O que eles fiz­eram foi acres­cen­tar algu­mas novas car­ac­terís­ti­cas ao padrão ante­rior K&R C.

As prin­ci­pais mudanças foram a inclusão de pro­tóti­pos de função, a padroniza­ção das bib­liote­cas e a adição de algu­mas palavras-chave como enum, const, volatile, signed, void (isso mesmo, estas palavras-chave não exis­tiam for­mal­mente antes do padrão ANSI C).

A maio­ria do código com­pi­lado em K&R C, com­pila em ANSI C, com algu­mas exceções. Para tratar estas exceções, foi cri­ado o #define __STDC__, que dev­e­ria ser imple­men­tado por padrão em todos os com­pi­ladores ANSI C. Veja no exem­plo abaixo o pro­tótipo da função soma() nos padrões ANSI C e K&R C.

1
2
3
4
5
#if __STDC__
extern int soma(int a, int b);
#else
extern int soma();
#endif

Todos os com­pi­ladores mod­er­nos supor­tam ANSI C. E ter um pro­grama com­patível com ANSI C sig­nifica que este será provavel­mente portável para qual­quer arquite­tura de hard­ware que pos­sua um com­pi­lador ANSI C disponível.

O PADRÃO C99

Na década de 90 a ISO cor­rigiu alguns detal­hes e pub­li­cou em 1999 o ISO/IEC 9899:1999, que ficou con­hecido como C99. Um draft do padrão pode ser visto aqui.

Den­tre as alter­ações, podemos destacar a inclusão de funções inline, var­iáveis “long long”, suporte para comen­tários de uma linha, além de não assumir int quando não é especi­fi­cado o retorno da função.

Por exem­plo, o código abaixo esta de acordo com o padrão C89, mas não com­pila de acordo com o padrão C99:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "stdio.h"
 
/* Retorna indice do maior elemento do array */
maior(long buf[], int qtd)
{
    long m = 0;
    int i, ind = -1;
 
    for (i = 0; i < qtd; i++) {
        if (buf[i] > m) {
            m = buf[i];
            ind = i;
        }
    }
 
    return(ind);
}
 
main(void)
{
    int m = -1;
 
    long buf[] = { 1234, 3456, 7345, 5897 };
 
    if ((m = maior(buf, 4)) >= 0)
        printf("Maior elemento buf[%d]=%ld\n", m, buf[m]);
    else
        printf("Maior elemento nao encontrado\n", buf[m]);
 
    return 0;
}

Para com­pi­lar de acordo com o padrão C99, algu­mas lin­has pre­cisam ser alteradas:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include "stdio.h"
 
int maior(long long buf[], int qtd);
 
// Retorna indice do maior elemento do array
inline int maior(long long buf[], int qtd)
{
    long long m = 0;
    int i, ind = -1;
 
    for (i = 0; i < qtd; i++) {
        if (buf[i] > m) {
            m = buf[i];
            ind = i;
        }
    }
 
    return(ind);
}
 
int main(void)
{
    int m = -1;
 
    long long buf[] = { 1234, 3456, 7345, 5897 };
 
    if ((m = maior(buf, 4)) >= 0)
        printf("Maior elemento buf[%d]=%lld\n", m, buf[m]);
    else
        printf("Maior elemento nao encontrado\n", buf[m]);
 
    return 0;
}

Para com­pi­lar, foi necessário alterar os retornos de função, declarando explici­ta­mente “int”.

Além disso, fize­mos algu­mas alter­ações per­mi­ti­das no padrão C99. Alter­amos todas as var­iáveis “long” para “long long”, usamos comen­tários de uma linha com “//” e declar­amos a função maior() como “inline”. 

Com estas alter­ações o código ficou com­patível com o padrão C99, mas perdeu a com­pat­i­bil­i­dade como padrão ANSI C (C89).

O FUTURO PADRÃO C1X

C1X é um nome não-oficial para um tra­balho que começou em 2007, com o obje­tivo de revisar e definir um novo padrão para a lin­guagem C. Algu­mas das alter­ações pro­postas podem ser encon­tradas no site da Wikipedia.

Algu­mas adições me pare­ce­ram bem inter­es­santes: uso das palavras-chave _Generic para declarar uma função que pode rece­ber difer­entes tipos de dados e _Atomic para definir que o acesso à deter­mi­nada var­iável deve ser atômico; a sub­sti­tu­ição da função gets() pela gets_s(), cuja imple­men­tação é bem mais segura; imple­men­tação de estru­turas e unions anôn­i­mas; etc.

Claro que o padrão atual (C99) é bem maduro, e você dev­e­ria usá-lo em todos os seus pro­je­tos. O novo padrão pre­tende adi­cionar novas fun­cional­i­dades para mel­ho­rar a vida do desen­volve­dor. Eu par­tic­u­lar­mente gostaria de ver um mecan­ismo de trata­mento de erros ao estilo try-catch-throw do C++. De qual­quer forma, deve levar ainda um tempo para o padrão sair, e mais um tempo para os com­pi­ladores imple­mentarem.

Nen­hum dos doc­u­men­tos ofi­ci­ais dos padrões esta disponível gra­tuita­mente na inter­net para down­load. Mas podemos baixar ver­sões ini­ci­ais da especi­fi­cação, ATAs de reunião e aden­dos. Esta wiki tem algu­mas infor­mações inter­es­santes com links para doc­u­men­tos rela­ciona­dos aos padrões.

Um abraço,

Ser­gio Prado

  • Diogo Luvi­zon

    Muito inter­es­sante!
    No dia-a-dia não damos tanta importân­cia a estes detal­hes, mas eu ja tive alguns prob­le­mas com padrões da lin­guagem C uti­lizando o com­pi­lado da CCS para PIC.

  • http://www.heltai.com.br Vini­cius Heltai

    Exce­lente pub­li­cação. As car­ac­ter­is­ti­cas evo­lu­ti­vas de cada lin­guagem de pro­gra­mação se torna base dos apren­diza­dos, con­hec­i­men­tos e aper­feiçoa­mento.
    São car­ac­ter­is­ti­cas de metodolo­gias ino­vado­ras do con­hec­i­mento.
    Parabens Ser­gio..
     
    Abraços
     
    Vini­cius Heltai

  • http://murilo.wordpress.com Murilo Adri­ano

    Bom artigo, porém em C++ não existe finally.

    • http://sergioprado.org ser­gio­prado

      Olá Murilo,

      É ver­dade! Finally só em java… Valeu pela dica!

      Abraços!

  • @St0rm_W0lf

     
    Come­cei a ler agora os arti­gos do seu site, e estou ado­rando os temas e a forma como infor­mação é trans­mi­tida.
     
    Valeu e parabéns
    Cyph3k

  • Paiva

    Oi Ser­gio, tudo bem? Tenho alguns livros sobre C/C++, porém, nen­hum deles fala sobre pro­gra­mação e cri­ação de estru­turas, ou como são chamadas infor­mal­mente “Esqueleto de Pro­gra­mas” para Win­dows ou GNU/Linux.
    Como uti­lizar C/C++, nesse caso, C++ (OOP), para con­struir sis­temas aplica­tivos, e tornar a lin­guagem mais uti­lizável, nessa área, é claro?
     
    Obrigado.

  • Rick

    Ótimo artigo! Parabéns e obrigado.

Navegue
Creative Commons Este trabalho de Sergio Prado é licenciado pelo
Creative Commons BY-NC-SA 3.0.