<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>C : coups de cœur et coups de gueule</title>
	<atom:link href="https://blog.developpez.com/kirilenko/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.developpez.com/kirilenko</link>
	<description>Write in C!</description>
	<lastBuildDate>Sat, 20 Apr 2013 16:54:09 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.42</generator>
	<item>
		<title>Récursivité en C, épidémie ou hérésie ?</title>
		<link>https://blog.developpez.com/kirilenko/p11930/divers/recursivite-en-c-epidemie-ou-heresie</link>
		<comments>https://blog.developpez.com/kirilenko/p11930/divers/recursivite-en-c-epidemie-ou-heresie#comments</comments>
		<pubDate>Sat, 20 Apr 2013 16:12:40 +0000</pubDate>
		<dc:creator><![CDATA[Kirilenko]]></dc:creator>
				<category><![CDATA[Divers]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[main]]></category>
		<category><![CDATA[récursion]]></category>
		<category><![CDATA[récursivité]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/kirilenko/?p=12</guid>
		<description><![CDATA[Une récursion pour les gouverner tous Voilà quelques temps que je n&#8217;avais plus utilisé ce média ; j&#8217;avais posté un article similaire sur une plateforme perdue, mais, n&#8217;ayant pas reçu réellement de retour, je me suis dit qu&#8217;il serait intéressant de centraliser tous mes petits articles ici, de manière à renvoyer uniformément les visiteurs sur cette page. Au départ, il s&#8217;agissait ici de parler uniquement de programmation système ; le sort en a décidé autrement. [&#8230;]]]></description>
				<content:encoded><![CDATA[<h2>Une récursion pour les gouverner tous</h2>
<p>Voilà quelques temps que je n&rsquo;avais plus utilisé ce média ; j&rsquo;avais posté un article similaire sur une plateforme perdue, mais, n&rsquo;ayant pas reçu réellement de retour, je me suis dit qu&rsquo;il serait intéressant de centraliser tous mes petits articles ici, de manière à renvoyer uniformément les visiteurs sur cette page. Au départ, il s&rsquo;agissait ici de parler uniquement de programmation système ; le sort en a décidé autrement.</p>
<p>En attendant, vous allez devoir me pardonner pour cette digression, qui ne devrait pas vraiment avoir de répercussion sur les visites, ceci dit. Voilà une nouvelle catégorie, « Divers », qui devrait accueillir nombre de mes réflexions inutiles (sur les forums, il est difficile de se lâcher sans se faire taper sur les doigts).</p>
<p>Qu&rsquo;on se mette d&rsquo;accord, aujourd&rsquo;hui, c&rsquo;est d&rsquo;un véritable phénomène qu&rsquo;on va parler. Une habitude étrange que quelques débutants ont prise : effectuer une récursion sur la fonction <em>main</em>. Ce sera notre prétexte pour explorer tout le vaste sujet de la récursivité en C. Je ne sais pas qui le leur a inculqué (ou plutôt, qui n&rsquo;a pas fait son boulot en le leur empêchant) ; toujours est-il que cela fait frémir la plupart des programmeurs « habitués » sur les forums. Si ce n&rsquo;est pas votre cas, c&rsquo;est inquiétant. Du moins, on va essayer de voir si c&rsquo;est le cas. Et surtout, pourquoi.</p>
<p><span id="more-12"></span></p>
<h2>Une récursion pour les trouver</h2>
<p>Vous êtes ici, sur un billet qui parle du C, et on vous parle d&rsquo;algorithmique ? Voilà qui semble, à première vue, plutôt contradictoire. Après tout, les gens qui font du C sont plutôt branchés sur le matériel. C&rsquo;est ça, le (faux) bas niveau. Seulement, la récursivité, c&rsquo;est, avant toute chose, une manière particulière de définir un algorithme donné, en le définissant par rapport à une entrée plus simple du problème. En programmation, on parlera de récursivité lorsqu&rsquo;une fonction s&rsquo;appelle elle-même. Parfois, il y a même des cas de récursivité croisée, ou deux fonctions s&rsquo;appellent mutuellement. Un exemple plutôt connu est la suite d&rsquo;Hofstadter.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">int female(int n)<br />
{<br />
&nbsp; &nbsp; if (n == 0) return 1;<br />
&nbsp; &nbsp; return n - male(female(n - 1));<br />
}<br />
<br />
int male(int n)<br />
{<br />
&nbsp; &nbsp; if (n == 0) return 0;<br />
&nbsp; &nbsp; return n - female(male(n - 1));<br />
}</div></div>
<p>Prenons maintenant l&rsquo;exemple (sérieux) d&rsquo;un algorithme calculant la <strong>factorielle</strong> d&rsquo;un nombre entier naturel. Vous pouvez la définir de deux manières différentes :</p>
<p>1) <strong>Itérativement</strong> : n! = 1 * 2 * &#8230; * n.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">int factorial_1(int n)<br />
{<br />
&nbsp; &nbsp; int r = 1, i;<br />
&nbsp; &nbsp; for (i = 1; i &amp;lt; n; i++) r *= i;<br />
&nbsp; &nbsp; return r;<br />
}</div></div>
<p>2) <strong>Récursivement</strong> : n! = 1 si n = 0 et n * (n &#8211; 1)! si n &gt; 0.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">int factorial_2(int n)<br />
{<br />
&nbsp; &nbsp; if (n == 0) return 1;<br />
&nbsp; &nbsp; return n * factorial_2(n - 1);<br />
}</div></div>
<p>Dès ces cas d&rsquo;école, les puristes commencent à remettre en cause l&rsquo;efficacité de la solution récursive. En effet, par nature, le C est assez proche de la machine. Chaque appel de fonction nécessite, en théorie, la création d&rsquo;un <strong>cadre de pile</strong> (en pratique, certaines de ces fonctions peuvent être <em>inlinées</em> par le compilateur, c&rsquo;est-à-dire en ajoutant le code directement dans la fonction appelante). </p>
<p>Ce n&rsquo;est pas une opération particulièrement légère, et, dès qu&rsquo;on se met à penser à la micro-optimisation, il vaut mieux éviter. En dehors de la performance, cela pose un autre problème : celui de la mémoire. Il faut bien voir que toutes les variables automatiques, les registres de base et de retour notamment, doivent être stockés sur la pile, et ce pour chaque récursion en cours.</p>
<p>En conséquence, le compilateur essaye de transformer des cas récursifs simples en boucles (qui, au final, auront l&rsquo;air d&rsquo;un branchement inconditionnel, équivalent à un vulgaire <em>goto</em>). Il est bien connu que tout appel récursif peut être converti en itératif, par l&rsquo;intermédiaire de piles (en recodant la pile d&rsquo;appels en fait), mais, naturellement, ça n&rsquo;aurait pas de sens pour le compilateur de faire ce genre d&rsquo;optimisations. Cependant, supposez que vous ayez choisi de coder la factorielle de cette manière :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">int factorial_3(int r, int n)<br />
{<br />
&nbsp; &nbsp; if (n == 0) return r;<br />
&nbsp; &nbsp; return factorial_2(r * n, n - 1);<br />
}</div></div>
<p>Parce que <em>r</em> indique les résultats de la récursivité au fur et à mesure, on dit qu&rsquo;il sert d&rsquo;<strong>accumulateur</strong>. En outre, on remarque ici que l&rsquo;appel récursif peut être facilement évité : il suffit de changer la valeur de <em>r</em> et de <em>n</em> à chaque fin de branchement. Mettons-nous à la place du compilateur optimisant (c&rsquo;est le cas de la plupart des compilateurs « grands publics » comme <em>gcc</em>, <em>clang</em> ou <em>icc</em>). Voilà comment il pourrait réécrire le code.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">int factorial_4(int r, int n)<br />
{<br />
I1:<br />
&nbsp; &nbsp; if (n == 0) return r;<br />
&nbsp; &nbsp; r = r * n;<br />
&nbsp; &nbsp; n = n - 1;<br />
&nbsp; &nbsp; goto I1;<br />
}</div></div>
<p>Je ne suis pas certain que beaucoup d&rsquo;entre vous aimerait maintenir ce genre de code, mais, pour la bêtise absolue d&rsquo;un ordinateur, ce n&rsquo;est pas dérageant. Au contraire, comme sa fainéantise est légendaire, il va se réjouir de pas avoir à créer un nouveau cadre de pile à chaque fois qu&rsquo;on décrémente <em>n</em>. On parle dans ce cas de <strong>récursivité terminale</strong>, et ce n&rsquo;est pas le cas de la fonction <em>factorial_2</em> ci-dessus. Bref, tout ça pour dire quoi ? Que la récursivité, c&rsquo;est intrinsèquement de l&rsquo;algorithmique. Ça fait plaisir aux férus de la programmation fonctionnelle, mais ça ne devrait pas atteindre nos points d&rsquo;entrée&#8230; Enfin, en théorie.</p>
<p><!--more--></p>
<h2>Une récursion pour les amener tous</h2>
<p>Venons-en au fait. Enfin, presque. Oui, parce que je voulais vous présenter mon nouveau jeu en console puissant. Du coup, j&rsquo;ai fait une jolie interface avec une fonction juste pour le menu. Voilà à quoi ressemble notre bête :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#include <br />
<br />
int menu(void)<br />
{<br />
&nbsp; &nbsp; int n;<br />
&nbsp; &nbsp; puts(&quot;Que voulez-vous faire ?\n&quot;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot; 1 - Manger un caillou.\n&quot;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot; 2 - Lécher un stylo.\n&quot;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot; 3 - Appeler un koala.\n<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;Votre choix ?&quot;);<br />
&nbsp; &nbsp; scanf(&quot;%d&quot;, &amp;amp;n);<br />
&nbsp; &nbsp; if (n &nbsp;3) return menu();<br />
&nbsp; &nbsp; return n;<br />
}</div></div>
<p>Sauf que, si je laisse ça comme ça, il y a danger. Danger que la pile explose, en réalité. Elle a une taille limitée, et un utilisateur malicieux pourrait même exploiter ces débordements pour écrire par-dessus certaines données (mais ça rentre dans des techniques d&rsquo;exploitation plutôt sordides). Dans une certaine mesure, même dans les langages fonctionnels (oui, oui), on évite généralement les systèmes récursifs pour lire des données structurées comme les tableaux. Pour les listes ou les arbres, c&rsquo;est différent, mais, même en C, la question se pose.</p>
<p>En fait, toutes ces histoires de puristes restent extrêmement subjectives. Notre fonction <em>menu</em> ci-dessus croît selon un majorant en <em>O(n)</em>. En revanche, il existe certaines fonctions qui ont une complexité bien moindre. C&rsquo;est par exemple le cas de la <strong>recherche dichotomique</strong>, qui permet de rechercher une valeur dans un tableau trié en complexité logarithmique (par le biais du paradigme « diviser pour régner »). Ainsi, cela ne posera pas trop de problème à un programmeur d&rsquo;écrire :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">int search_divide(const int *a, int left, int right, int element)<br />
{<br />
&nbsp; &nbsp; int mid;<br />
&nbsp; &nbsp; if (left &amp;gt; right) return -1;<br />
&nbsp; &nbsp; mid = (left + right) / 2;<br />
&nbsp; &nbsp; if (a[mid] &amp;gt; element) return search_divide(a, left, mid - 1);<br />
&nbsp; &nbsp; if (a[mid] &amp;lt; element) return search_divide(a, mid + 1, right);<br />
&nbsp; &nbsp; return mid;<br />
}</div></div>
<p>Pourtant, la solution itérative est tout aussi limpide. Du coup, la récursivité se justifie encore plus facilement quand on est obligé de sortir un modèle à base de pile pour la conversion. C&rsquo;est par exemple le cas des <em>parsers</em> d&rsquo;expression, quand on doit explorer des caractères sémantiques par définition récursifs (comme les parenthèses dans un <em>parser</em> d&rsquo;expressions mathématiques).</p>
<p><!--more--></p>
<h2>&#8230; et dans les ténèbres les lier</h2>
<p>Il est temps de discuter ce qui devait être notre objet initial, mais, qui, finalement, est passé au travers de ma langue bavarde. Oui, parce qu&rsquo;il existe des pauvres fous (fuyez !) qui, non contents de faire de la récursion sur des menus, le font dans la fonction <em>main</em> ! On voit quelques fois un exemple de récursivité croisée, quand les débutants veulent revenir au début du programme, alors qu&rsquo;ils sont perdus dans des structures conditionnelle imbriquées.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">void foo(void)<br />
{<br />
&nbsp; &nbsp; /* Some stuff */<br />
&nbsp; &nbsp; if (repeat) main();<br />
}</div></div>
<p>Le mieux, dans ce genre de code, c&rsquo;est de passer à la boucle (en ré-arrangeant le code dans un premier temps, évidement&#8230;) ; cela pour deux raisons majoritairement :</p>
<li>L&rsquo;interfaçage avec le C++ : la norme de ce langage interdit spécifiquement d&rsquo;appeler <em>main</em>.</li>
<li>Les implémentations non conformes : en embarqué, certains compilateurs non standards insèrent des bouts de code d&rsquo;initialisation au début du programme (c&rsquo;est du déjà vu).</li>
<p>Pour finir, j&rsquo;aimerais simplement vous montrer un petit contre-exemple, que quelqu&rsquo;un proposait sur <em>Usenet</em>. Le principe est d&rsquo;utiliser la récursivité sur la fonction <em>main</em> pour simplifier le traitement des arguments en ligne de commande. Personnellement, je n&rsquo;ai jamais eu affaire à ce genre de contraintes, mais on ne sait jamais sur quoi on peut tomber (sans <em>getopt</em>, certains sont perdus !).</p>
<p>Voilà qui clôt magistralement mal notre modeste billet. J&rsquo;espère ne pas trop vous avoir ennuyé, et n&rsquo;oubliez pas de rediriger le prochain inconscient par ici&#8230; non sans l&rsquo;avoir châtié sévèrement, évidemment !</p>
<p>PS : Comme habituellement, ça fait toujours du plaisir de voir ses posts commentés&#8230; Même si vous n&rsquo;avez rien à dire, ça donne l&rsquo;impression qu&rsquo;on ne parle pas dans le vide. Sauf si vous ne voulez plus jamais me voir appuyer sur une touche du clavier, auquel cas je vous laisse déverser votre haine dans le silence. Le train de vos injures roule sur les rails de mon indifférence, disait un proverbe populaire. <img src="https://blog.developpez.com/kirilenko/wp-includes/images/smilies/icon_smile.gif" alt=":-)" class="wp-smiley" /></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Le bloc de contrôle de processus</title>
		<link>https://blog.developpez.com/kirilenko/p10651/manipulation-des-processus/le_bloc_de_controle_de_processus</link>
		<comments>https://blog.developpez.com/kirilenko/p10651/manipulation-des-processus/le_bloc_de_controle_de_processus#comments</comments>
		<pubDate>Sat, 14 Jan 2012 17:37:26 +0000</pubDate>
		<dc:creator><![CDATA[Kirilenko]]></dc:creator>
				<category><![CDATA[Manipulation des processus]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Le système d&#8217;exploitation dispose d&#8217;une table de processus, permettant de gérer de manière globale chaque processus. Chaque processus possède une entrée, appelée bloc de contrôle de processus. Il contient diverses informations, comme : &#8211; son PID ; &#8211; son PPID ; &#8211; son état ; &#8211; son contexte processeur (état des registres) et mémoire (adresses de l&#8217;espace d&#8217;adressage) ; &#8211; ses critères d&#8217;ordonnancement ; &#8211; les fichiers ouverts.]]></description>
				<content:encoded><![CDATA[<p>Le système d&rsquo;exploitation dispose d&rsquo;une <strong>table de processus</strong>, permettant de gérer de manière globale chaque processus.<br />
Chaque processus possède une entrée, appelée <strong>bloc de contrôle</strong> de processus. Il contient diverses informations, comme :</p>
<p>&#8211; son PID ;<br />
&#8211; son PPID ;<br />
&#8211; son état ;<br />
&#8211; son contexte processeur (état des registres) et mémoire (adresses de l&rsquo;espace d&rsquo;adressage) ;<br />
&#8211; ses critères d&rsquo;ordonnancement ;<br />
&#8211; les fichiers ouverts.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Etats d&#8217;un processus</title>
		<link>https://blog.developpez.com/kirilenko/p10650/manipulation-des-processus/etats_d_un_processus</link>
		<comments>https://blog.developpez.com/kirilenko/p10650/manipulation-des-processus/etats_d_un_processus#comments</comments>
		<pubDate>Sat, 14 Jan 2012 17:34:49 +0000</pubDate>
		<dc:creator><![CDATA[Kirilenko]]></dc:creator>
				<category><![CDATA[Manipulation des processus]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Un processus Unix peut-être caractérisé par son état. Il existe communément trois états : &#8211; élu ; &#8211; bloqué ; &#8211; prêt. Un processus est dans l&#8217;état élu lorsqu&#8217;il s&#8217;exécute, après avoir obtenu le processeur. Il est bloqué lorsqu&#8217;il est en attente, par exemple d&#8217;une lecture de disque. Il est dans l&#8217;état prêt lorsqu&#8217;il est n&#8217;est pas en attente, mais qu&#8217;il n&#8217;a pas le processeur. Il attend simplement que ce soit son tour. Le passage [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Un processus Unix peut-être caractérisé par son <strong>état</strong>. Il existe communément trois états :</p>
<p>&#8211; <strong>élu</strong> ;<br />
&#8211; <strong>bloqué</strong> ;<br />
&#8211; <strong>prêt</strong>.</p>
<p>Un processus est dans l&rsquo;état élu lorsqu&rsquo;il s&rsquo;exécute, après avoir obtenu le processeur.<br />
Il est bloqué lorsqu&rsquo;il est en attente, par exemple d&rsquo;une lecture de disque.<br />
Il est dans l&rsquo;état prêt lorsqu&rsquo;il est n&rsquo;est pas en attente, mais qu&rsquo;il n&rsquo;a pas le processeur. Il attend simplement que ce soit son tour.</p>
<p>Le passage de l&rsquo;état prêt à l&rsquo;état élu constitue l&rsquo;opération d&rsquo;<strong>élection</strong>.<br />
Le passage de l&rsquo;état élu à l&rsquo;état bloqué constitue l&rsquo;opération de <strong>blocage</strong>.<br />
Le passage de l&rsquo;état bloqué à l&rsquo;état prêt constitue l&rsquo;opération de <strong>déblocage</strong>.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Qu&#8217;est-ce que la programmation système ?</title>
		<link>https://blog.developpez.com/kirilenko/p10648/concepts-generaux-de-programmation-systeme/qu_est_ce_que_la_programmation_systeme</link>
		<comments>https://blog.developpez.com/kirilenko/p10648/concepts-generaux-de-programmation-systeme/qu_est_ce_que_la_programmation_systeme#comments</comments>
		<pubDate>Fri, 13 Jan 2012 15:39:36 +0000</pubDate>
		<dc:creator><![CDATA[Kirilenko]]></dc:creator>
				<category><![CDATA[Concepts généraux de programmation système]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[La programmation système vise au développement de programmes systèmes, qui sont relativement bas niveaux : interface avec le noyau et les bibliothèques systèmes sont donc des points en faisant partie. UNIX est un terrain parfait pour la programmation système, puisque créé à cet effet à l&#8217;origine. Deux ypes de fonction permettent la programmation système : &#8211; les fonctions de la bibliothèque standard de C (libc) ; &#8211; les appels-systèmes, fonctions d&#8217;interface entre le noyau et [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>La programmation système vise au développement de programmes systèmes, qui sont relativement bas niveaux : interface avec le noyau et les bibliothèques systèmes sont donc des points en faisant partie.<br />
UNIX est un terrain parfait pour la programmation système, puisque créé à cet effet à l&rsquo;origine.</p>
<p>Deux ypes de fonction permettent la programmation système :<br />
&#8211; les fonctions de la bibliothèque standard de C (libc) ;<br />
&#8211; les appels-systèmes, fonctions d&rsquo;interface entre le noyau et les applications. Lors de son appel, le noyau effectue un déroutement (trap) qui bascule en mode noyau.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fork déchiffré</title>
		<link>https://blog.developpez.com/kirilenko/p10645/lenvironnement/fork_dechiffre</link>
		<comments>https://blog.developpez.com/kirilenko/p10645/lenvironnement/fork_dechiffre#comments</comments>
		<pubDate>Wed, 11 Jan 2012 18:36:32 +0000</pubDate>
		<dc:creator><![CDATA[Kirilenko]]></dc:creator>
				<category><![CDATA[L&#039;environnement]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[La fonction fork() peut paraître un peu surprenante au premier abord. La question que vous pouvez légitimement vous poser est : que fait un fork() ? Cet appel-système alloue un bloc de contrôle dans la table des processus, copie certaines des informations du bloc du père (fichiers ouverts, répertoire courant, etc.) dans le bloc du fils. Il alloue un PID au processus fils. Le noyau alloue le segment texte du processus, dans lequel il place [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>La fonction fork() peut paraître un peu surprenante au premier abord. La question que vous pouvez légitimement vous poser est : que fait un fork() ?</p>
<p>Cet appel-système alloue un bloc de contrôle dans la table des processus, copie certaines des informations du bloc du père (fichiers ouverts, répertoire courant, etc.) dans le bloc du fils. Il alloue un PID au processus fils.<br />
Le noyau alloue le segment texte du processus, dans lequel il place son code. Le segment de données et la pile ne seront alloués que plus tard, lorsque l&rsquo;utilisateur tentera de les utiliser. Cette technique, appelée copy on write, permet de réduire les coûts de l&rsquo;allocation. Enfin, l&rsquo;état du processus est mis à la valeur exécution.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Terminaison de processus</title>
		<link>https://blog.developpez.com/kirilenko/p10641/manipulation-des-processus/terminaison_de_processus</link>
		<comments>https://blog.developpez.com/kirilenko/p10641/manipulation-des-processus/terminaison_de_processus#comments</comments>
		<pubDate>Tue, 10 Jan 2012 18:21:15 +0000</pubDate>
		<dc:creator><![CDATA[Kirilenko]]></dc:creator>
				<category><![CDATA[Manipulation des processus]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Un processus peut se terminer suite à l&#8217;appel de la fonction : void exit(int status); de stdlib.h. status est un entier, qui permet d&#8217;indiquer la valeur de retour du processus. Conventionnellement, on utilise la valeur de 0 pour indiquer une sortie correcte, ou une autre valeur pour indiquer l&#8217;erreur. Exemple : #include &#60;stdio.h&#62; #include &#60;stdlib.h&#62; #include &#60;unistd.h&#62; #include &#60;sys/types.h&#62; &#160; void task(void) { &#160; puts(&#34;Child process... end.&#34;); &#160; exit(0); } &#160; int main(void) { &#160; [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Un processus peut se terminer suite à l&rsquo;appel de la fonction :</p>
<p><code class="codecolorer text default"><span class="text">void exit(int status);</span></code></p>
<p>de stdlib.h.</p>
<p>status est un entier, qui permet d&rsquo;indiquer la valeur de retour du processus. Conventionnellement, on utilise la valeur de 0 pour indiquer une sortie correcte, ou une autre valeur pour indiquer l&rsquo;erreur. Exemple :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#include &lt;stdio.h&gt; <br />
#include &lt;stdlib.h&gt; <br />
#include &lt;unistd.h&gt; <br />
#include &lt;sys/types.h&gt; <br />
&nbsp;<br />
void task(void) { <br />
&nbsp; puts(&quot;Child process... end.&quot;); <br />
&nbsp; exit(0); <br />
} <br />
&nbsp;<br />
int main(void) { <br />
&nbsp; pid_t p; <br />
&nbsp;<br />
&nbsp; p = fork(); <br />
&nbsp;<br />
&nbsp; switch (p) { <br />
&nbsp; &nbsp; case -1: <br />
&nbsp; &nbsp; &nbsp; perror(&quot;fork&quot;); <br />
&nbsp; &nbsp; &nbsp; break; <br />
&nbsp; &nbsp; case 0: <br />
&nbsp; &nbsp; &nbsp; task(); <br />
&nbsp; &nbsp; &nbsp; break; <br />
&nbsp; &nbsp; default: <br />
&nbsp; &nbsp; &nbsp; puts(&quot;Father process...&quot;); <br />
&nbsp; &nbsp; &nbsp; break; <br />
&nbsp; } <br />
&nbsp; return EXIT_SUCCESS; <br />
}</div></div>
<p>On pourra récupérer la valeur envoyée à exit par un processus fils par son processus père, et ce sera l&rsquo;objet d&rsquo;un prochain article plus complet, concernant la synchronisation des processus.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Les variables d&#8217;environnement</title>
		<link>https://blog.developpez.com/kirilenko/p10640/lenvironnement/les_variables_d_environnement</link>
		<comments>https://blog.developpez.com/kirilenko/p10640/lenvironnement/les_variables_d_environnement#comments</comments>
		<pubDate>Tue, 10 Jan 2012 18:00:53 +0000</pubDate>
		<dc:creator><![CDATA[Kirilenko]]></dc:creator>
				<category><![CDATA[L&#039;environnement]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Une application peut s&#8217;exécuter dans des contextes très différents. Le répertoire courant, le répertoire personnel de l&#8217;utilisateur, le type de terminal, entres autres, sont indiqués par des variables d&#8217;environnement. En pratique, les variables d&#8217;environnement sont des chaînes de caractère sous la forme NOM=VALEUR. Elles sont modifiées par les fichiers d&#8217;initialisation du shell par exemple. Pour accéder aux variables d&#8217;environnement d&#8217;un processus dans un programme codé en C, il suffit d&#8217;utiliser le tableau environ, une variable [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Une application peut s&rsquo;exécuter dans des contextes très différents. Le répertoire courant, le répertoire personnel de l&rsquo;utilisateur, le type de terminal, entres autres, sont indiqués par des <strong>variables d&rsquo;environnement</strong>.</p>
<p>En pratique, les variables d&rsquo;environnement sont des chaînes de caractère sous la forme NOM=VALEUR. Elles sont modifiées par les fichiers d&rsquo;initialisation du shell par exemple.</p>
<p>Pour accéder aux variables d&rsquo;environnement d&rsquo;un processus dans un programme codé en C, il suffit d&rsquo;utiliser le tableau environ, une  variable globale. Il faut le déclarer en début de programme car il n&rsquo;est pas définit dans les fichiers d&rsquo;en-têtes standards.</p>
<p><code class="codecolorer text default"><span class="text">extern char **environ;</span></code></p>
<p>Il contient des chaînes de caractères se terminant par le caractère &lsquo;\0&prime;, et se termine lui-même par un pointeur nul.</p>
<p>Exemple de programme listant les variables d&rsquo;environnement du processus principal.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#include &lt;stdio.h&gt; <br />
#include &lt;stdlib.h&gt; <br />
&nbsp;<br />
extern char **environ; <br />
&nbsp;<br />
int main(void) { <br />
&nbsp; unsigned i; <br />
&nbsp; for (i = 0; environ[i] != NULL; i++) { <br />
&nbsp; &nbsp; fprintf(stdout, &quot;%s\n&quot;, environ[i]); <br />
&nbsp; } <br />
&nbsp; return EXIT_SUCCESS; <br />
}</div></div>
<p>Notez qu&rsquo;il existe également une autre solution pour lister les variables d&rsquo;environnement du processus principal, bien que moins recommandée. En effet, il est possible d&rsquo;utiliser un troisième argument de la fonction main(), envp, qui se comporte comme environ. Exemple :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#include &lt;stdio.h&gt; <br />
#include &lt;stdlib.h&gt; <br />
&nbsp;<br />
int main(int argc, char *argv[], char *envp[]) { <br />
&nbsp; unsigned i; <br />
&nbsp; for (i = 0; envp[i] != NULL; i++) { <br />
&nbsp; &nbsp; fprintf(stdout, &quot;%s\n&quot;, envp[i]); <br />
&nbsp; } <br />
&nbsp; (void) argc; <br />
&nbsp; (void) argv; <br />
&nbsp; return EXIT_SUCCESS; <br />
}</div></div>
<p>Bon codage !</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Quelques fonctions bien utiles</title>
		<link>https://blog.developpez.com/kirilenko/p10637/manipulation-des-processus/quelques_fonctions_bien_utiles</link>
		<comments>https://blog.developpez.com/kirilenko/p10637/manipulation-des-processus/quelques_fonctions_bien_utiles#comments</comments>
		<pubDate>Mon, 09 Jan 2012 18:41:20 +0000</pubDate>
		<dc:creator><![CDATA[Kirilenko]]></dc:creator>
				<category><![CDATA[Manipulation des processus]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Bonjour, Après avoir introduit la création des processus, je souhaitais vous présenter quelques fonctions qui sont utiles, notamment lors du débogage de votre application. Je cite : pid_t getpid(void); qui retourne le PID du processus courant. pid_t getppid(void); qui retourne le PID du processus père du processus courant. uid_t getuid(void); qui retourne l&#8217;UID (identificateur de l&#8217;utilisateur qui a créé le processus) du processus courant. gid_t getgid(void); qui retourne le GID (identificateur du groupe auquel appartient [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Bonjour,</p>
<p>Après avoir introduit la création des processus, je souhaitais vous présenter quelques fonctions qui sont utiles, notamment lors du débogage de votre application.</p>
<p>Je cite :</p>
<p><code class="codecolorer text default"><span class="text">pid_t getpid(void);</span></code></p>
<p>qui retourne le PID du processus courant.</p>
<p><code class="codecolorer text default"><span class="text">pid_t getppid(void);</span></code></p>
<p>qui retourne le PID du processus père du processus courant.</p>
<p><code class="codecolorer text default"><span class="text">uid_t getuid(void);</span></code></p>
<p>qui retourne l&rsquo;UID (identificateur de l&rsquo;utilisateur qui a créé le processus) du processus courant.</p>
<p><code class="codecolorer text default"><span class="text">gid_t getgid(void);</span></code></p>
<p>qui retourne le GID (identificateur du groupe auquel appartient l&rsquo;utilisateur) du processus courant.</p>
<p>Exemple qui résument les fonctions que je viens de vous présenter :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#include &lt;stdio.h&gt; <br />
#include &lt;stdlib.h&gt; <br />
#include &lt;unistd.h&gt; <br />
#include &lt;sys/types.h&gt; <br />
&nbsp;<br />
int main(void) { <br />
&nbsp; pid_t p; <br />
&nbsp;<br />
&nbsp; p = fork(); <br />
&nbsp;<br />
&nbsp; switch (p) { <br />
&nbsp; case -1: <br />
&nbsp; &nbsp; perror(&quot;fork&quot;); <br />
&nbsp; &nbsp; break; <br />
&nbsp; case 0: <br />
&nbsp; &nbsp; fprintf(stdout, &quot;I'm father process.\n&quot;); <br />
&nbsp; &nbsp; break; <br />
&nbsp; default: <br />
&nbsp; &nbsp; fprintf(stdout, &quot;I'm child process, PID = #%u&quot; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot; ; PPID = #%u ; UID = #%u ; GID = #%u\n&quot;, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(unsigned)getpid(), (unsigned)getppid(), &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(unsigned)getuid(), (unsigned)getgid()); <br />
&nbsp; } <br />
&nbsp; return EXIT_SUCCESS; <br />
}</div></div>
<p>Bon codage !</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Création de processus</title>
		<link>https://blog.developpez.com/kirilenko/p10636/manipulation-des-processus/creation_de_processus</link>
		<comments>https://blog.developpez.com/kirilenko/p10636/manipulation-des-processus/creation_de_processus#comments</comments>
		<pubDate>Mon, 09 Jan 2012 18:16:58 +0000</pubDate>
		<dc:creator><![CDATA[Kirilenko]]></dc:creator>
				<category><![CDATA[Manipulation des processus]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Bonjour, Dans ce billet, qui est le premier de ce blog, je souhaitais vous présenter mon projet. Je suis passionné par la programmation en C, et plus particulièrement par l&#8217;aspect « bas niveau » de celle-ci. Le C a été créé pour développer le système d&#8217;exploitation UNIX, sur lequel sont basés la plupart des OS couramment usés. La programmation système consiste au développement d&#8217;applications qui font partie intégrante du système d&#8217;exploitation. C&#8217;est ce type de [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Bonjour,</p>
<p>Dans ce billet, qui est le premier de ce blog, je souhaitais vous présenter mon projet. Je suis passionné par la programmation en C, et plus particulièrement par l&rsquo;aspect « bas niveau » de celle-ci. Le C a été créé pour développer le système d&rsquo;exploitation UNIX, sur lequel sont basés la plupart des OS couramment usés.<br />
La programmation système consiste au développement d&rsquo;applications qui font partie intégrante du système d&rsquo;exploitation. C&rsquo;est ce type de programmation, opposée aux programmes utilisateurs, que je voulais vous faire découvrir dans ce blog.</p>
<p>Ce premier billet commence par la pratique, et avec la création des processus. Les processus représentent l&rsquo;image d&rsquo;un programme à un instant donné (état des registres entres autres).</p>
<p>Chaque processus possède un espace d&rsquo;adressage donné, dans lequel il peut lire et écrire. Cet espace est divisé en trois grandes parties (segment texte, segment données, pile).</p>
<p>En C et sous un système d&rsquo;exploitation basé sur UNIX, il est possible de créer un processus grâce à la fonction conforme POSIX.1 :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#include &lt;unistd.h&gt; <br />
&nbsp;<br />
pid_t fork(void);</div></div>
<p>Le type pid_t (déclaré dans sys/types.h) représente l&rsquo;identificateur d&rsquo;un processus (appelé PID pour Process IDentifier). En l&rsquo;occurrence, la fonction renvoie trois valeurs, suivant ce qui s&rsquo;est passé lors de l&rsquo;exécution de cet appel-système :</p>
<ul>
<li>-1 en cas d&rsquo;erreur, et errno est positionnée pour contenir le code de l&rsquo;erreur (à savoir EAGAIN ou ENOMEM) ;</li>
<li>0 si on est dans le processus père ;</li>
<li>une autre valeur, positive, indiquant le PID du processus créé (appelé processus fils).</li>
</ul>
<p>Premier exemple pratique :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#include &lt;stdio.h&gt; <br />
#include &lt;stdlib.h&gt; <br />
#include &lt;unistd.h&gt; <br />
#include &lt;sys/types.h&gt; <br />
&nbsp;<br />
int main(void) { <br />
&nbsp; pid_t p; <br />
&nbsp;<br />
&nbsp; p = fork(); <br />
&nbsp;<br />
&nbsp; switch (p) { <br />
&nbsp; case -1: <br />
&nbsp; &nbsp; perror(&quot;fork&quot;); <br />
&nbsp; &nbsp; break; <br />
&nbsp; case 0: <br />
&nbsp; &nbsp; fprintf(stdout, &quot;I'm father process.\n&quot;); <br />
&nbsp; &nbsp; break; <br />
&nbsp; default: <br />
&nbsp; &nbsp; fprintf(stdout, &quot;I'm child process, PID = #%u&quot;, (unsigned)p); <br />
&nbsp; &nbsp; break; <br />
&nbsp; } <br />
&nbsp; return EXIT_SUCCESS; <br />
}</div></div>
<p>Le résultat peut varier selon l&rsquo;ordre d&rsquo;exécution des processus sur votre machine. Notez que la synchronisation des processus pourrait permettre une certaine unité, et ce sera l&rsquo;objectif d&rsquo;un des prochains articles !</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
