Historique

Table des matières

Origines
CPL
BCPL
B
C
Évolutions
K&R C
C++
ANSI C
Standard C++
C99
K&R C
int implicite
Paramètres

Origines

C a trois ancêtres : CPL, BCPL et B.

CPL

CPL (pour Combined Programming Language) a été conçu au début des années 60 par les universités de Cambridge et de Londres. C'était un grand projet académique consistant à créer un langage englobant beaucoup de concepts. CPL devait aussi être fortement typé, c'est-à-dire que les données n'étaient pas traitées comme des tas de bits (qu'elles sont), mais comme de vrais nombres entiers, réels, booléens, caractères, tableaux, listes... qu'on ne peut pas mélanger ; comme les pommes et les oranges chez les professeurs de physique.

Aujourd'hui, le typage fort est une des caractèristiques du langage Ada, qui est souvent opposé à C. Mais CPL était trop complexe pour l'époque et il semble que jamais personne n'ait réussi à terminer l'écriture d'un compilateur. En tout cas ce langage a disparu sans laisser de trace quelque-part dans les années 70.

Réf. : LinuxGuruz, Wikipedia

BCPL

BCPL (pour Basic CPL) a été conçu à Cambridge en 1966 par Martin Richards. L'année suivante il alla au MIT et écrivit un premier compilateur. BCPL est une version fortement simplifiée de CPL avec notamment un seul type de donnée, le mot machine, c'est-à-dire le nombre typique de bits qu'un ordinateur traite en une instruction machine (addition, soustraction, multiplication, copie...) La notion est devenue un peu floue avec les processeurs actuels qui peuvent traiter des données de toutes sortes de tailles, mais on peut encore dire que les Pentium et PowerPC sont 32 bits tandis que les Alpha, POWER et Itanium sont 64 bits. À l'époque c'était plus varié et ce n'était pas forcément des puissances de 2 multiples de 8 ; par exemple 40 bits, 36 bits, 18 bits ou 16 bits.

BCPL s'accomode de toutes ces tailles de mot machine. Il est donc à la fois portable et proche du matériel, donc efficace pour la programmation système. BCPL a servi à écrire divers systèmes d'exploitation de l'époque, dont un (TripOS) qui s'est retrouvé partiellement porté sur l'Amiga pour devenir la partie AmigaDOS du système.

Aujourd'hui cependant, je ne suis pas sûr que BCPL soit encore utilisé par quelqu'un d'autre que son inventeur. En tout cas je ne connais aucun programme actuel écrit en BCPL. C'est peut-être dû au fait que C a repris et étendu les qualités de BCPL.

Réf. : Manuel BCPL,
exemple de http://www.lysator.liu.se/c/clive-on-history.html :

MANIFEST ${ TOPFACT = 10 $} // Equivalent of "const int TOPFACT = 10"
LET infact (n) = VALOF
$(
  LET f, j = 1., 0.

  FOR i = 0 TO n             // Declares i for the next block only
  $(
    f #*:= j;                // := is assign, = is compare
    fact!i := f;             // assignment doesn't return a value
    j #+:= 1.
  $)
  RESULTIS f
$)
AND fact = VEC TOPFACT;      // As in B, allocates 0 to TOPFACT

B

B a été créé par Ken Thompson vers 1970 dans les laboratoires Bell d'AT&T. L'année précédente il avait écrit en assembleur la première version de UNIX sur un PDP-7 contenant 8 kilo-mots de 18 bits. Après il voulut proposer un langage sur UNIX. Il semble qu'il ait d'abord pensé à porter FORTRAN, mais que très vite (en une semaine) il conçut son propre langage : B.

B est une simplification de BCPL (3 caractères de moins), un peu forcée par les limitations du PDP-7. Mais la syntaxe très sobre de B toute en lettres minuscules correspond surtout aux goûts de Thompson. C a repris la syntaxe de B avec un minimum de changements.

B a été porté et utilisé sur quelques autres systèmes. Mais cette même année 1970, le succès du projet UNIX justifia l'achat d'un PDP-11. Celui-ci avait des mots machine de 16 bits mais il était aussi capable de traiter des octets (24 Ko de RAM en tout) dans chacun duquel pouvait être stocké un caractère. B ne traitait que des mots machines, donc le passage de 18 à 16 bits n'était pas problématique, mais il était impossible de traiter efficacement les caractères de 8 bits. Pour bien exploiter les capacités de la machine, B a donc commencé à être étendu en ajoutant un type pour les caractères...

Réf. : Thompson's B Manual,
exemple de http://www.lysator.liu.se/c/clive-on-history.html :

infact (n)
{
  auto f, i, j;   /* no initialization for auto variables */
  extrn fact;     /* "What would I do differently if designing
                   *  UNIX today?  I'd spell creat() with an e."
                   *  -- Ken Thompson, approx. wording */

  f = 1.;         /* floating point constant */
  j = 0.;
  for (i = 0; i <= n; ++i) {
    fact[i] = f =#* j;      /* note spelling =#* not #*= */
    j =#+ 1.;               /* #+ for floating add */
  }

  return (f);     /* at least, I think the () were required */
}

TOPFACT = 10;   /* equivalent of #define, allows numeric values only */
fact[TOPFACT];

C

C a été développé par un collègue de Ken Thompson, Dennis Ritchie qui pensait d'abord faire uniquement un New B ou NB. Mais Ritchie ajouta plus que les caractères : par exemple les tableaux, les pointeurs ou les nombres à virgule flottante. 1972 fût l'année de développement la plus productive et sans doute l'année de baptême de C. En 1973 C fut suffisamment au point pour que 90% de UNIX puisse être récrit avec. En 1974 les laboratoires Bell ont accordés des licences UNIX aux universités et c'est ainsi que C a commencé à être distribué.

Réf. : The Development of the C Language, Very early C compilers and language,
exemple de http://www.lysator.liu.se/c/clive-on-history.html :

float infact (n) int n;
{
  float f = 1;
  int i;
  extern float fact[];

  for (i = 0; i <= n; ++i)
    fact[i] = f *= i;

    return d;
  }

#define TOPFACT 10
float fact[TOPFACT+1];

Ken Thompson (assis) et Dennis Ritchie devant un PDP-11 fonctionnant avec UNIX vers 1972 :
Photo noir-blanc de Ken et Dennis devant un PDP-11

Évolutions

Une fois rendu public, le langage C a peu changé. D'un autre côté, C++ est une gigantesque extension de C ; ceci explique peut-être cela. D'autres langages comme Objective C, Java, JavaScript ou C# ont largement repris la syntaxe de C, mais sans être compatibles.

1978 - K&R C

#include <stdio.h>
main(argc,
     argv)
int argc;
char ** argv;
{
 printf("hello, world\n");
}

La première évolution de C qui nous concerne directement date de 1978 lorsque Brian Kernighan et Dennis Ritchie ont publié la première édition du livre : The C Programming Language. Il décrit ce qu'on appelle actuellement le K&R C, C traditionnel, voire vieux C. Peu après sa publication, de très nombreux compilateurs C ont commencé à apparaître. Les programmes portables écrits dans les années 80 sont donc en K&R C. En fait même les programmes récents qui doivent être très portables, comme GCC 3, sont encore compilables en K&R C. Des systèmes commerciaux comme HP/UX n'ont parfois qu'un compilateur K&R C en standard.

1983 - C++

#include <iostream.h>
int main(int argc,
         char * argv[])
{
 cout << "hello, world"
      << endl;
 return 0;
}

À partir de 1980 Bjarne Stroustrup a étendu C avec le concept de classe. Ce langage étendu a d'abord été appelé C with Classes puis C++ en 1983. C++ a énormément évolué, mais en restant le plus compatible possible avec C. En fait on tombe même parfois sur des programmes C++ qui utilisent tellement peu les possibilités du langage qu'on ne voit pas bien la différence avec un programme C (telnet sur Debian).

1989 - ANSI C

#include <stdio.h>
main(int argc,
     char * argv[])
{
 printf("hello, world\n");
 return 0;
}

Un comité de standardisation a été créé en 1983 pour éviter que les quelques ambiguïtés et insuffisances du K&R C ne conduisent à des divergences importantes entre les compilateurs. C'est ce qui a donné en 1989 le standard appelé ANSI C. Il a repris quelques bonnes idées de C++ tout en restant compatible avec K&R C.

Le degré de compatibilité atteint est suffisant pour que Kernighan et Ritchie n'aient eu qu'à adapter légèrement la seconde édition du The C Programming Language pour qu'il décrive ANSI C. En plus selon Stroustrup tous les exemples de cette seconde édition sont aussi des programmes C++.

Depuis les années 90, ANSI C est l'évolution la plus utilisée de C.

1998 - Standard C++

#include <iostream>
int main(int argc,
         char * argv[])
{
 std::cout << "hello, world"
           << std::endl;
}

C++ a évolué très longtemps. Ce n'est qu'en 1998, 8 ans après la création d'un comité, que le standard ISO C++ a été officiellement publié. Mais ce standard est tellement complexe (et défectueux) qu'en 2002 je n'en connais pas encore de mise en œuvre vraiment complète et correcte. La compatibilité avec C reste très bonne. Les syntaxes obsolètes et problématiques de K&R C ont cependant été abandonnées.

1999 - C99

#include <stdio.h>
int main(int argc,
         char * argv[])
{
 printf("hello, world\n");
}

Le dernier né de l'histoire est C99 (standard ISO de 1999) qui est une petite évolution de l'ANSI C de 1989. Les évolutions ne sont pas compatibles avec C++ et n'ont pas attiré beaucoup d'intérêt.

GCC supporte assez bien C99. Or comme le noyau Linux utilise assez à fond les possibilités de GCC, on peut considérer que les versions récentes de Linux sont écrites en C99, plus des extensions propres à GCC. Côté compatibilité, le support des syntaxes obsolètes de K&R C a été abandonné.

K&R C

On tombe encore facilement sur du K&R C. Par exemple le programme C le plus court qu'on rencontre dans la nature est :

main(){}

Ce programme est en fait un programme K&R C typique car :

int implicite

La pratique de ne pas écrire explicitement le type int est en fait courante en K&R C :

/* Exemple en vieux C */
*g;
main() {
  auto i; g=&i; *g=0; return i;
}
/* Exemple en C moderne */
int *g;
int main(void) {
  int i; g=&i; *g=0; return i;
}

Il faut noter qu'en B on n'indiquait pas non plus le type puisqu'il n'y avait que le mot machine, qui est devenu int en C...

Paramètres

La différence la plus importante entre ANSI C et K&R C se situe dans les déclarations et définitions de fonctions :

f(); /* déclaration de f, returne un int (implicite),
        paramètres non spécifiés */

main() { return f(2,0); }

int f(a, b)  /* définition de f */
int a, b;    /* avec le type des paramètres donné après */
{
  return a * b;
}

Seul le nom des paramètres était donné dans la liste des paramètres. Leur type était déclaré en-dessous, avant l'accolade ouvrante.

De ce fait, les prototypes n'existaient pas en K&R C. On pouvait déclarer une fonction, mais cela ne précisait pas le type de ses paramètres.

Comme le type des paramètres n'est pas connu au moment de l'appel, il y a promotion de type lors du passage du paramètre, comme avant une opération. Les char et les short sont notamment promus en int et les float en double.

On trouve encore les mêmes promotions sur les paramètres de printf correspondant aux ... de int printf(const char*,...);. Ce qui explique qu'on puisse écrire short s; printf("%d", s); alors que %d attend un int.


© 2002 Marc Mongenet, pour le Groupe des Utilisateurs Linux du Léman (GULL).