main()
?printf()
peut recevoir différents types d'arguments ?Par exemple :
int f(); /* declaration de f(), renvoyant un int, pas de prototype */
int f(void);/* declaration de f(), renvoyant un int, prototype (0 arg) */
int f(void) /* definition de f() avec declaration avec prototype */
{
return 42;
}
int f(x) /* definition de f() avec declaration sans prototype */
int x;
{
return x;
}
int f() /* definition de f() avec declaration sans prototype */
{
return 42;
}
Ce qui n'est pas possible :
int
.
printf()
.
(cf. 9.6).
int fa(int a, char const * const b);
int fb(int, char const * const);
Les noms de paramètre sont optionnels, mais il est fortement conseillé de les laisser. Cela donne une bonne indication sur leurs rôles.
Les fonctions de la bibliothèque ont également leur prototype.
Avant l'utilisation de celles-ci, il faut inclure les fichiers
d'en-tête contenant les prototypes.
Par exemple, le prototype de malloc()
se trouve dans
stdlib.h
.
Certains préfèrent ajouter le mot clé extern
au
prototype, afin de rester cohérent avec la déclaration des
variables globales.
Voir aussi les questions 9.3, 12.1, 13.5 et 14.16.
xxx.c
) dans un fichier d'en-tête
(xxx.h
). Ce dernier n'a plus alors qu'à être inclus dans
le code qui utilise ces fonctions. C'est le cas des fonctions de
la bibliothèque standard.
Voir aussi la question 13.5.
main()
?main()
renvoie toujours un int
.
Les prototypes valides sont :
int main(void);
int main(int argc, char * argv[]);
Tout autre prototype n'est pas du tout portable et ne doit jamais être utilisé (même s'il est accepté par votre compilateur).
En particulier, vous ne devez pas terminer la fontion
main()
sans retourner une valeur positive (non nulle en
cas d'erreur).
Les valeurs de retour peuvent être 0
,
EXIT_SUCCESS
ou EXIT_FAILURE
.
On pourra aussi rencontrer (sous Unix) le prototype suivant :
int main (int argc, char* argv[], char** arge);
dans le but d'utiliser les variables d'environnement du
shell actif. Ce n'est ni portable ni standard,
d'autant plus que les fonctions getenv()
,
setenv()
et putenv()
le sont et suffisent
largement.
Enfin, rappelons que le prototype suivant
int main () ;
est parfaitement valide en C++ (et est synonyme du premier présenté ici), mais ne l'est pas en C.
printf()
peut recevoir différents types d'arguments ?printf()
est une fonction à nombre variable de
paramètres. Son prototype est le suivant :
int printf(const char * format, ...);
Le type et le nombre des paramètres n'est pas défini dans le prototype, c'est le traitement effectué dans la fonction qui doit les vérifier.
Pour utiliser cette fonction, il est donc impératif d'inclure
l'en-tête <stdio.h>
.
Pour écrire une fonction de ce type, lire la question suivante (9.6).
<stdarg.h>
.
Le prototype d'une fonction à nombre variable de paramètres doit
contenir au moins un paramètre explicite, puis se termine par ...
Exemple :
int f(int nombre, ...);
Il faut, d'une façon ou d'une autre, passer dans les paramètres le
nombre d'arguments réellement transmis.
On peut le faire en donnant ce nombre explicitement (comme
printf()
), ou passer la valeur NULL
en dernier.
Attention toutefois avec la valeur NULL
dans ce cas.
En effet, NULL
n'est pas nécessairement une valeur du
type pointeur mais une valeur qui donne un pointeur
nul si elle est affectée ou passée ou comparée à un type
pointeur. Le passage d'une valeur à un paramètre n'est pas une
affectation à un pointeur mais une affectation qui obéit aux lois
spéciales pour les paramètres à nombre variable (ou pour les
paramètres d'une fonction sans prototype). Les lois de promotion
pour les types arithmétiques sont appliquées). Si NULL
est
défini par
#define NULL 0
alors (int)0
est passé à la fonction. Si un pointeur n'a
pas la même taille qu'un int
ou si un pointeur nul n'est
pas représenté par « tous les bits 0 » le passage d'un 0 ne passe
donc pas de pointeur nul. La méthode portable est
donc
f(toto,titi,(void*)NULL);
ou
f(toto,titi,(void*)0);
C'est le seul cas où il faut caster NULL parce qu'il ne s'agit pas d'un contexte syntactique « de pointeur », seulement d'un contexte « de pointeur par contrat ».
Après cela, les fonctions va_start()
,
va_arg()
et va_end()
permettent de parcourir
la liste des paramètres.
Voici un petit exemple :
#include <stdarg.h>
int vexemple(int nombre, ...){
va_list argp;
int i;
int total = O;
if(nombre < 1)
return 0;
va_start(argp, nombre);
for (i = 0; i < nombre; i++) {
total += va_arg(argp, int);
}
va_end(argp);
return total;
}
Merci à Horst Kraemer pour ces remarques.
void echange(int * a, int * b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
faq-fclc 5/3/2002 (8h 59:04)