« Exercices en langage C/Notions de base » : différence entre les versions

Contenu supprimé Contenu ajouté
Réparation.
DannyS712 (discussion | contributions)
m <source> -> <syntaxhighlight> (phab:T237267)
 
Ligne 32 :
Un programme C commence par l'exécution d'une fonction <code>main</code>. Il existe deux prototypes standards pour la fonction <code>main</code> : <code>int main(void)</code> et <code>int main(int argc, char* argv[])</code>. Nous utilisons le plus simple car nous n'avons pas besoin de <code>argc</code> ni <code>argv</code>. Remarquons que les deux prototypes indiquent que <code>main</code> retourne un entier de type <code>int</code>. Nous retournons 0 (zéro), valeur conventionnelle pour indiquer que le programme est terminé sans erreur. Voici notre '''définition''' de la fonction <code>main</code> :
 
<sourcesyntaxhighlight lang="C">
/* Solution en retournant 0 */
int main(void)
Ligne 38 :
return 0;
}
</syntaxhighlight>
</source>
 
Nous pouvons aussi utiliser pour le code retour la constante '''EXIT_SUCCESS''' de ''stdlib.h'' plus parlante que 0.
<sourcesyntaxhighlight lang="C">
#include <stdlib.h>
 
Ligne 48 :
return EXIT_SUCCESS;
}
</syntaxhighlight>
</source>
}}
 
Ligne 65 :
 
La fonction a appeler :
<sourcesyntaxhighlight lang="c">
int un(void)
{
return 1;
}
</syntaxhighlight>
</source>
 
Pour compiler et exécuter :
Ligne 88 :
On définit la fonction <code>un</code> avant la fonction <code>main</code>. Dans <code>main</code>, à l'aide de l'opérateur d'appel de fonction <code>()</code>, on procède à l'appel de fonction <code>un()</code>, dont on retourne immédiatement la valeur.
 
<sourcesyntaxhighlight lang="c">
int un(void)
{
Ligne 98 :
return un();
}
</syntaxhighlight>
</source>
 
Remarques qualité :
* Lorsque on définit une fonction de la sorte, elle est par défaut '''extern''' (visible de l'extérieur). Dans un projet plus important, elle pourrait donc être appelée à la place d'une autre portant le même nom. Pour limiter sa visibilité en interne, il faudrait utiliser le mot clé '''static'''. <code>static int un(void)</code>.
* Que se passe-t-il si l'on définit la fonction <code>un</code> après <code>main</code> ? En compilant <code>main</code>, le compilateur va remarquer que l'on appelle une fonction <code>un</code> dont il ne sait rien. Cela ne l'empêche pas de compiler le programme ! ('''sans l'option -Wall il ne signalera rien !''') Le compilateur fait comme si <code>un</code> avait été déclarée par : <code>extern int un()</code>. Il y a déclaration implicite de fonction, alors que le compilateur ne sait rien de l'implémentation réelle de la fonction ! Par chance, la déclaration explicite correspond au prototype <code>int un(void)</code> et le programme suivant fonctionne. Il vaut mieux éviter ces mécanismes hasardeux, en demandant au compilateur d'être strict et en utilisant l'option '''-Wall'''.
<sourcesyntaxhighlight lang="c">
/* Réponse dangereuse */
int main(void)
Ligne 114 :
return 1;
}
</syntaxhighlight>
</source>
*Ce qui donnera à la compilation
<pre>
Ligne 124 :
 
Si l'on souhaite tout de même mettre la fonction ''main'' en premier, il aurait fallu avertir le compilateur en utilisant un prototype : la signature de la fonction, placé avant le ''main''.
<sourcesyntaxhighlight lang="c">
static int un(void);
 
Ligne 136 :
return 1;
}
</syntaxhighlight>
</source>
}}
 
Ligne 158 :
On utilise le préprocesseur pour inclure <code>stdio.h</code> car le prototype de <code>printf</code> se trouve dans <code>stdio.h</code>. On passe la chaîne de caractères <code>"hello, world\n"</code> à l'appel de <code>printf</code>. On remarque que la chaîne est terminée par un caractère de nouvelle ligne (<code>\n</code>). Sans cela, une fois le programme terminé, l'invite de commande risque d'être affichée à la suite du mot ''world'' au lieu de se trouver au début d'une nouvelle ligne.
 
<sourcesyntaxhighlight lang="c">
/* Bonne réponse */
#include <stdio.h>
Ligne 167 :
return 0;
}
</syntaxhighlight>
</source>
 
'''Remarques'''
* la fonction printf() retourne le nombre de caractère écrits dans le flux de sortie, ici j'ai décidé de ne pas utiliser ce code retour, je le signale en castant à void la fonction. L'outil qualité lint signale toute fonction retournant une valeur qui n'est pas affectée à une variable ou ignoré explicitement. Cela permet d'éviter l'erreur qui consiste à oublier de traiter un code retour de fonction.
* Que se passe-t-il si l'on omet le <code>#include <stdio.h></code> ? Le compilateur va remarquer que l'on appelle une fonction <code>printf</code> dont il ne sait rien. Cela ne l'empêche pas de compiler le programme ! Le compilateur fait comme si <code>printf</code> avait été déclarée par : <code>extern int printf()</code>. Il y a déclaration implicite de fonction, alors que le compilateur ne sait rien de l'implémentation réelle de la fonction ! Si l'on omet d'inclure les prototypes des fonctions appelées, on risque donc d'appeler ces fonctions avec des '''paramètres incompatibles sans avertissement du compilateur''' :
<sourcesyntaxhighlight lang="C">
/* Appel de printf aberrant risquant de compiler sans avertissement
faute d'avoir inclu stdio.h. Un crash à l'exécution est probable. */
Ligne 180 :
return 0;
}
</syntaxhighlight>
</source>
 
L'option de gcc -Wall signale ce problème à la compilation par ce message :
Ligne 189 :
Pour détecter le problème, c'est-à-dire que l'entier <code>123</code> (de type <code>int</code>) est passé au lieu d'une chaîne de caractères (de type <code>const char*</code>), le compilateur doit voir le prototype de <code>printf</code>, qui est : <code>int printf(const char*, ...)</code>. Ce qui nous intéresse avec le <code>#include <stdio.h></code>, c'est que le préprocesseur génère la sortie suivante en entrée du compilateur :
 
<sourcesyntaxhighlight lang="C">
/* Ce que le compilateur voit */
/* Contenu de stdio.h... */
Ligne 203 :
return 0;
}
</syntaxhighlight>
</source>
 
Notons que certains compilateurs ont une connaissance implicite des fonctions très communes comme <code>printf</code>. Ainsi, même sans voir le prototype de <code>printf</code>, certaines versions de GCC génèrent un avertissement, à moins d'utiliser la commande de compilation suivante : <code>gcc -fno-builtin -o hello.exe hello.c</code>. L'option '''-Wall''' active l'option --fno-builtin.
Ligne 230 :
Pour avoir accès aux arguments en ligne de commande, on utilise la seconde définition standard de <code>main</code>, qui a pour premier paramètre le nombre d'arguments <code>argc</code>, et pour second paramètre le vecteur d'arguments <code>argv</code>. Notons que sur Unix, le nom de l'exécutable lui-même (<code>./arg</code>) est un argument, donc <code>argc</code> vaut au moins 1. Le résultat recherché est <code>argc - 1</code>. Pour afficher un nombre entier, nous utilisons des caractères de conversion dans la chaîne de formatage passée à <code>printf</code>. Le caractère de conversion <code>d</code> suivant le caractère <code>%</code> indique que nous affichons un entier de type <code>int</code>.
 
<sourcesyntaxhighlight lang="c">
/* Bonne réponse */
#include <stdio.h>
Ligne 240 :
return EXIT_SUCCESS;
}
</syntaxhighlight>
</source>
 
}}