Notes sur le langage C
Date de publication : 29 avril 2009
X. Le type retourné par main()
X-A. Historique
XI. C'est quoi un prototype ?
XII. Bibliothèques de fonctions
XII-A. Bibliothèque statique
XII-B. Bibliothèque dynamique
XIII. Pourquoi ma fonction ne modifie pas ma variable ?
XIV. Les fonctions à nombre d'arguments variable
X. Le type retourné par main()
Bien que main() soit censé retourner un int, on voit quelquefois écrit
Qu'en est-il exactement ?
D'après la définition du langage C, dans un programme conforme, main() doit retourner int. D'ailleurs
un compilateur comme Borland C 3.1 en mode ANSI refuse void main() (error). Dans les mêmes
conditions, gcc qui émet un avertissement (warning).
X-A. Historique
Dès l'apparition du langage C, une des formes canoniques de main() était
l'autre étant la forme qui permet de récupérer les arguments de la ligne de commande.
Il faut bien comprendre qu'à cette époque, une fonction définie sans type de retour explicite, retournait
un int (c'est toujours le cas en C90, mais plus en C99 où le type doit être explicite). Le mot
clé 'void' n'existait pas.
|
Il n'y avait donc aucune raison d'utiliser une forme void main().
|
Ensuite, est venue la normalisation du langage C. (1989 ANSI, 1990 ISO). Dans le texte, les deux formes
canoniques sont décrites :
et
int main (int argc, char * * argv)
|
Il est précisé en remarque (dans la partie non normative) qu'il existe d'autres formes sans autres
précisions. Elles ne font donc pas partie de la norme, leur comportement est donc indéfini dans
le cadre d'un programme respectueux de la norme (dit 'strictement conforme').
XI. C'est quoi un prototype ?
Lorsqu'on défini une fonction,
on définit en même temps son interface, à savoir :
-
son nom (ici , f)
-
son type de retour (ici, int)
-
ses paramètres (ici, s, de type pointeur sur char)
Cet interface est aussi appelé prototype intégré. Il permet une utilisation de la fonction si l'appel
est placé après la définition (il n'y a pas de raison de faire autrement, sauf cas exceptionnels
et souvent douteux...) :
int f (char * s)
{
...
}
int main (void )
{
int x = f (" hello " );
}
|
Maintenant, dans le cas de compilation séparée, on doit 'détacher' le prototype et le placer dans un
fichier qui sera inclus à la fois dans le fichier d'implémentation de la fonction et dans le ou
les fichiers qui l'utilisent.
# include "f.h"
int f (char * s)
{
...
}
|
# include "f.h"
int main (void )
{
int x = f (" hello " );
}
|
Pour compléter, il est fortement recommandé de protéger les fichiers .h contre les inclusions multiples
avec une garde (guard) :
# ifndef H_F
# define H_F
int f (char * s);
# endif
|
XII. Bibliothèques de fonctions
Une bibliothèque (library) est une collection de fonctions mise à la disposition des programmeurs.
Elle se compose d'une interface matérialisée par un ou plusieurs fichiers d'entêtes (.h), et d'un
fichier d'implémentation qui contient le corps des fonctions (.lib, .a, .dll, .so etc.) sous forme
exécutable.
Il est aussi possible à un programmeur de 'capitaliser' son travail en réalisant des fonctions réutilisables
qu'il peut ensuite organiser en bibliothèques. Cette pratique est courante et encouragée.
La création physique d'une bibliothèque
est assez simple si on respecte quelques règles de conception, comme l'absence de globales,
la souplesse et l'autonomie. Elle nécessite un outil spécialisé (librarian) généralement livré avec
toute implémentation du langage C.
Une bibliothèque peut être statique ou dynamique (partagée).
XII-A. Bibliothèque statique
Une bibliothèque à édition de lien statique (.lib, .a etc.) est liée à l'application pour ne former qu'un
seul exécutable. La taille de celui-ci peut être importante, mais il a l'avantage d'être autonome.
Cette pratique a l'avantage de la simplicité, et elle ne requiert aucune action particulière de
la part d'un éventuel système lors de l'exécution du programme. Elle est très utilisée en programmation
embarquée (embedded).
XII-B. Bibliothèque dynamique
Une bibliothèque à édition de lien dynamique, est un fichier séparé (.dll, .so, ...) qui doit être livré
avec l'exécutable. L'intérêt est que plusieurs applications peuvent se partager la même bibliothèque,
ce qui est intéressant, surtout si sa taille est importante. Dans ce cas, les exécutables sont
plus petits. Autre avantage, les défauts de la bibliothèque peuvent être corrigés indépendamment
des applications. Ensuite, la correction est répercutée immédiatement sur toutes les applications
concernées par simple mise à jour de la bibliothèque dynamique.
Une application qui utilise une bibliothèque dynamique doit réaliser le lien avec la bibliothèque à l'exécution.
Pour cela, elle utilise des appels à des fonctions système spécifiques dans sa phase d'initialisation.
Les détails dépendent de la plate-forme.
XIII. Pourquoi ma fonction ne modifie pas ma variable ?
Il y a deux façon de modifier la valeur d'un objet (aka variable) avec une fonction :
-
Récupérer la valeur retournée par la fonction :
ou
avec
-
Passer l'adresse de la variable dont on veut modifier la valeur à la fonction :
avec
Si l'objet est un pointeur, la règle est la même :
avec
avec
|
Il n'y a aucune chance de modifier l'entier en faisant ceci :
|
|
De même, il n'y a aucune chance de modifier le pointeur en faisant cela :
|
XIV. Les fonctions à nombre d'arguments variable
Copyright © 2009 Emmanuel Delahaye.
Aucune reproduction, même partielle, ne peut être faite
de ce site ni de l'ensemble de son contenu : textes, documents, images, etc.
sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à
trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.