FAQ CConsultez toutes les FAQ

Nombre d'auteurs : 27, nombre de questions : 175, dernière mise à jour : 17 décembre 2010  Ajouter une question

 

Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums de www.developpez.com et de l'expérience personnelle des auteurs.

Je tiens à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes ; les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur, ou que vous souhaitez devenir rédacteur, lisez ceci .

Sur ce, je vous souhaite une bonne lecture.


SommaireLes fonctions et les variables globalesLes fonctions (8)
précédent sommaire suivant
 

Un prototype est la partie qui, dans la définition d'une fonction, définit les relations entre la fonction le monde extérieur. Par exemple dans :

Code C :
1
2
3
4
double f(double x, int n) 
{ 
    ... 
}
Toute la première ligne constitue le prototype de la fonction. Elle indique :

  • Le nom de la fonction : f
  • Le type de la valeur retournée : double
  • Le nombre de paramètres requis : 2 dont le premier de type double (x) et le deuxième de type int (n)

Une fonction avant d'être utilisée doit être déclarée. La déclaration permet au compilateur de s'assurer que la fonction sera toujours correctement utilisée dans le programme. Pour déclarer une fonction, il suffit de prendre son prototype puis d'ajouter un point-virgule à la fin.

Mis à jour le 23 mars 2009 Emmanuel Delahaye gl

Est-il possible de définir une fonction sans fournir le prototype ?

Oui, et c'était d'ailleurs le seul moyen de définir une fonction avant la normalisation du langage C, c'est-à-dire dans le C originel (K & R C). Voici un exemple de définition d'une fonction selon cette méthode :

Code C :
1
2
3
4
5
double f(x, n) 
double x; int n; 
{ 
    ... 
}
Et voici comment on devait déclarer la fonction :

Code C :
1
2
double f(); /* Les parenthèses, toujours vides, qui suivent f servent à indiquer que f est une fonction. */ 
/* Sans elles, la ligne définiraiô plutot une variable globale de type double nommée f.                  */
Ces méthodes ne permettent pas au compilateur de contrôler la validité des paramètres passées à une fonction à chaque appel à cause du manque de renseignement qu'elles lui fournissent d'où l'invention du prototype par l'ANSI.

Mis à jour le 20 septembre 2004 gl

Qu'est-ce qu'un prototype ?

Supposons que l'on veut écrire une fonction, reset, qui permette de mettre à 0 une variable de type int. Faisons donc :

Code c :
1
2
3
4
void reset(int n) 
{ 
    n = 0; 
}
L'extrait de code suivant :

Code c :
1
2
int a = 10; 
reset(a);
Ne met pas a à 0 (après l'appel reset(a), on aura donc toujours a = 10 !) car reset(a) ne fait que passer la valeur de a (ici 10) à la fonction reset qui copie ensuite cette valeur dans sa variable locale n puis met cette variable à 0 ! C'est donc n que la fonction modifie et non a !

Pour que la fonction reset puisse modifier la valeur de « la variable » qu'on lui a transmise, ce n'est pas la valeur de la variable qu'il faut lui fournir mais plutôt son adresse. Connaissant l'adresse de la variable, la fonction peut aussi bien lire que modifier sa valeur. Le bon code est donc :

Code c :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h> 
  
void reset(int * adr); 
  
int main(void) 
{ 
    int a = 10; 
  
    reset(&a); 
    printf("a = %d\n", a); /* affiche "a = 0" */ 
  
    return 0; 
} 
  
void reset(int * adr) 
{ 
    *adr = 0; 
}

Mis à jour le 29 janvier 2003 Bob Melem

Une fonction ne peut retourner au plus qu'une valeur, mais il est possible de créer une fonction qui retourne d'autres valeurs via un ou plusieurs paramètres. Par exemple :

Code C :
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
#include <stdio.h> 
#include <math.h> 
  
void decomposer_nombre(double x, double * ptr1, double * ptr2); 
  
int main(void) 
{ 
    double x, e, d; 
  
    printf("x = "); 
    scanf("%lf", &x); /* Supposons que l'utilisateur tape 2.5 */ 
  
    decomposer_nombre(x, &e, &d); /* On donne une entrée (x), on obtient deux sorties (e et d) */ 
  
    printf("e = %f\n", e); /* Pour x = 2.5, affiche e = 2.000000 */ 
    printf("d = %f\n", d); /* Pour x = 2.5, affiche d = 0.500000 */ 
  
    return 0; 
} 
  
void decomposer_nombre(double x, double * ptr1, double * ptr2) 
{ 
    /* Nous allons mettre dans *ptr1 la partie entière de x */ 
    /* et dans *ptr2 sa partie décimale                     */ 
  
    *ptr1 = floor(x); 
    *ptr2 = x - *ptr1; 
}
Cette fonction retourne deux valeurs, un indice de réussite (le retour de la fonction) et une valeur entière.

Mis à jour le 29 janvier 2003 Bob Melem

Une première méthode consiste à passer à la fonction un pointeur vers la zone mémoire destinée à contenir la chaîne à retourner. Par exemple :

Code C :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h> 
#include <string.h> 
  
void get_string(char * Buffer, size_t BufferLen) 
{ 
    /* On ne peut pas utiliser strcpy car cette fonction 
    ne permet pas d'indiquer le nombre max de caractères qu'on veut copier */ 
    strncpy(Buffer, "MaChaine", BufferLen); 
  
    /* Il est possible que Buffer n'ait pas pu contenir toute la chaine ... */ 
    Buffer[BufferLen - 1] = '\0'; 
} 
  
int main(void) 
{ 
    char Buffer[100]; 
  
    get_string(Buffer, sizeof(Buffer)); 
    printf("%s\n", Buffer); 
  
    return 0; 
}

Une autre façon de faire est de retourner un pointeur vers des caractères situées en mémoire globale. Par exemple :
  • À l'aide d'une chaîne statique :

    Code C :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <stdio.h> 
      
    const char * get_string(void) 
    {     
        return "MaChaine"; 
    } 
      
    int main(void) 
    { 
        printf("%s\n", get_string()); 
      
        return 0; 
    }
  • À l'aide d'une chaîne allouée dynamiquement :

    Code C :
    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
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <string.h> 
      
    char * alloc_string(void) 
    { 
        char * Buffer, s[] = "MaChaine"; 
      
        Buffer = malloc(strlen(s) + 1); 
      
        if (Buffer != NULL) 
            strcpy(Buffer, s); 
      
        return Buffer; 
    } 
      
    int main(void) 
    { 
        char * Buffer = alloc_string(); 
      
        if (Buffer != NULL) 
        { 
            printf("%s\n", Buffer); 
            free(Buffer); 
        } 
      
        return 0; 
    }

Mis à jour le 2 mars 2003 Bob gl LFE Melem

Voici un exemple de fonction, func, ne prenant aucun argument et qui retourne un pointeur sur une fonction de type int f(const char * s) (par exemple puts) :

Code c :
1
2
3
4
int (*func(void))(const char *) 
{ 
    return puts; 
}
Le prototype de func qui paraît pour le moins ésotérique a en fait été obtenu par la méthode suivante : func retournant un pointeur, func(void) vaut ce pointeur et *func(void) la chose pointée. Cette chose pointée est une fonction qui prend en argument un const char * et qui retourne un int donc (*func(void))(const char *) est de type int d'où le prototype de f : int (*func(void))(const char *).

Bien entendu, ici encore un typedef allège énormément l'écriture.

Code c :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h> 
  
typedef int F(const char *); 
  
F * func(void); 
  
int main(void) 
{ 
    func()("Bonjour."); /* <=> puts("Bonjour."); */ 
    return 0; 
} 
  
F * func(void) 
{ 
    return puts; 
}

Mis à jour le 15 juin 2009 Alp gege2061

Les ... dans la liste des paramètres d'une fonction indiquent que la fonction peut accepter 0, un ou plusieurs paramètres à la place. Parmi les paramètres de la fonction, il doit cependant y a voir au moins un qui explicite (fixé). Les macros va_start(), va_arg() et va_end() définies dans stdarg.h permettent de parcourir les paramètres. Dans l'exemple ci-dessous, on parcourt les paramètres jusqu'à en rencontrer un qui vaut 0.

Code C :
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
#include <stdio.h> 
#include <stdarg.h> 
  
void printf_total(const char * format, ...); 
  
int main(void) 
{ 
    print_total("Le total est : %d\n", 1, 2, 3, 4, 0); 
    return 0; 
} 
  
/* Fonction print_total : affiche la somme des arguments */ 
  
void printf_total(const char * format, ...) 
{ 
    int total = 0; 
    va_list ap; 
    int arg; 
  
    va_start(ap, format); 
  
    while ((arg = va_arg(ap, int)) != 0) 
        total += arg; 
  
    printf(format, total); 
  
    va_end(ap); 
}

Mis à jour le 1er février 2003 LFE

Le système présenté ici permet de fournir à une fonction une valeur qui regroupe un ensemble de flags (drapeaux) souvent utilisés pour permettre à l'utilisateur de fournir un nombre variable d'options sans utiliser le système de fonction à nombre variable d'arguments (va_list). Pour cela, il faut commencer par définir les différentes options possibles :

Code C :
1
2
3
4
enum { 
    OPTION1 = 1 << 0, 
    OPTION2 = 1 << 1 
};
Notez que les valeurs des options doivent être des puissances de deux pour avoir un bit égal à 1 et les autres égaux à 0. D'après l'énumération précédente, OPTION1 vaut 1 soit 000001 en binaire et OPTION2 vaut 000010, alors pour passer les deux paramètres à une fonction dont le prototype serait le suivant :

Code C :
void foo(int options)
on écrit :

Code C :
foo(OPTION1 | OPTION2)
D'après les propriétés du OU binaire, la fonction va recevoir la valeur 000011. Ensuite, il va falloir décomposer cette valeur pour retrouver les différentes options. Il faut faire l'opération inverse du OU binaire grâce au ET binaire :

Code C :
options & OPTION1
La valeur de cette expression est différente de 0 (soit vrai) si l'un des bits de OPTION1 se retrouve dans options. Il faut faire le test pour chacune des options proposées. Voici un code complet :

Code C :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h> 
  
enum { 
    OPTION1 = 1 << 0, 
    OPTION2 = 1 << 1 
}; 
  
void foo(int); 
  
int main(void) 
{ 
    foo(OPTION1 | OPTION2); 
    return 0; 
} 
  
void foo(int options) 
{ 
    if (options & OPTION1) 
        printf("OPTION1 trouve\n"); 
    if (options & OPTION2) 
        printf("OPTION2 trouve\n"); 
}

Mis à jour le 30 octobre 2005 gege2061

Comment accéder à un bit d'une variable ?

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2014 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

 
 
 
 
Partenaires

PlanetHoster
Ikoula