Rédaction tutoriel C

(auto)recrutement

a marqué ce sujet comme résolu.

@ Saroupille : avec la deuxième ligne de ton petit code tu entres déjà dans les aspect très pointus du C. L'explication d'un tel comportement fait appel à une notion de "point de séquence" assez barbare lorsqu'on n'a pas été préparé par avant.

Un cours qui arrive à présenter à terme un code de ce genre, et que l'apprenti comprenne sa spécificité, c'est un idéal. Et on n'en trouve pas des tonnes de cours de ce genre…

uknow

Je ne sais même pas de quoi tu parles. Pour moi ça fait parti des nombreux cas où le C à une sémantique ambiguë. Il faut faire un choix sur l'évaluation des expressions.

Le problème de ton code n'est pas dans l'ordre d'évaluation des expressions mais il modifie trois fois un même objet dans le même point de séquence.

Pour faire simple, un point de séquence c'est une étape à l'issue de laquelle tous les effets de bord sont résolus.

Si tu ne comprends pas ce que ces termes veulent dire, c'est toute une partie fondamentale du langage que tu n'as pas encore eu la possibilité d'explorer, et c'est un peu le défaut de la plupart des cours.

+0 -0

Personnellement, je veux bien essayer de faire un tuto qui montre pas à pas comment réécrire un allocateur mémoire simple (au hasard, first fit). Si je suis toujours motivé, ça pourra évoluer vers des algorithmes plus compliqués (buddy blocks) voire même vers de la garbage collection (en se mettant dans la peau de quelqu'un qui écrit un interpréteur pour un langage de haut niveau). Mes prérequis seront :

Personnellement, je préférerais des tutoriels sur l'allocation mémoire et les GC, qui expliqueraient la théorie, sans faire la moindre référence à un langage. Un truc qui expliquerait les principes et algorithmes, sans donner d'implémentations, en gros. Un peu comme pour mon tutoriel sur les OS : il n'y a pas le moindre code, et je ne propose pas d'apprendre à coder un OS.

Ça vous inspire quoi ? Quelqu'un est motivé pour faire un tuto qui présente le fonctionnement de la mémoire en général (registres, caches, RAM, disque, puis pile & tas), puis comment on interagit avec en C (malloc, variables locales, le qualificateur register, puis stdio.h et mmap) qui serait un prérequis de mon TP ?

Je veux bien tenter d'écrire un truc sur la gestion du cache, mais ce sera totalement indépendant du C. Du genre le tutoriel qui expliquerait des trucs bien connus comme la différence entre tableaux de structures et structures de tableaux, ou le genre de choses qu'on peut voir sur le blog mechanical sympathy.

Rien que le chapitre sur les algorithmes cache oblivious sera bien abstrait, sans aucun lien avec le C. A la limite, je crois que ce serait plutôt une meilleure idée d'implémenter les algorithmes en question en Python ou en Java histoire de bien faire comprendre que non, contrairement aux idées reçues, ce genre de chose n'est pas limité au langages de bas niveau et au C.

Autre idée de tuto : un cours général sur les fonctions, version bas niveau. Ce cours s'appuierait sur celui concernant la mémoire, montrerait que le code d'une fonction est stockée en RAM (donc qu'on peut faire des pointeurs de fonctions et expliquerait la notion), que les paramètres sont passés sur la pile (et montrerait l'erreur classique de renvoyer l'adresse d'une variable locale), et que c'est ce mécanisme qui permet d'appeler des fonctions C depuis d'autres langages et réciproquement (avec pourquoi pas un exemple ou un TP).

Dans le genre tellement dépendant de l'architecture que tu passeras ton temps à décrire les ABI de chaque ISA sans pouvoir vraiment donner d'explications générales, ça vaut son pesant de cacahouète ! Franchement, je vois pas l’intérêt, et c'est d'ailleurs pour cela que je me suis limité à ce que j'ai écrit dans mon chapitre sur les structures de contrôle de "Fonctionnement d'un ordinateur de zéro".

A la limite, je crois que cela aurait sa place dans un tutoriel d'assembleur, mais pas ailleurs.

+0 -0

Alors peut-être qu'il y a différentes manière de voir ce problème.

Pour ma part, je le vois ainsi : il existe $4$ sémantiques pour évaluer ce genre d'expression.

En reprenant l'exemple précédent ça donnerait :

  • 2*2
  • 2*3
  • 3*2
  • 4*4 (gcc)

Il faut en choisir une. Mais sur ce genre d'expression, rien ne garantie qu'un compilateur donnera le même résultat qu'un autre.

En vérité il y a plus de valeurs possibles. Ton expression est assez complexe à interpréter, n'oublie pas que tu fais appel à l'opérateur ++ qui modifie l'objet avant de passer au point de séquence suivant (dans la même instruction en quelque sorte).

Les expressions résultant à un comportement indéfini, bien connues sont :

1
2
i = i++;
a[i] = i++;

Il faut en choisir une.

Je dirai que non, il ne faut jamais écrire de telles choses pour des fins autres que d'expliquer ce qu'est un comportement indéfini.

Mais sur ce genre d'expression, rien ne garantie qu'un compilateur donnera le même résultat qu'un autre.

Justement, si le langage lui même ne spécifie pas de comportement pour ce cas de figure.

+0 -0

Le code de Saroupille est un UB au moins en C++ ? Je ne crois pas que le C++ ait diverge du C sur ce point.

Je confirme que c'est un UB en C aussi.

C11 :

If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings⁸⁴⁾. […]

C99 :

Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored.

84) This paragraph renders undefined statement expressions such as

1
2
       i = ++i + 1;
       a[i++] = i;

while allowing

1
2
       i=i+1;
      a[i] = i;
+0 -0

Qu'affiche printf ?

1
2
3
i = 2;
i = (i++)*(i++);
printf("i : \n", i);

Saroupille

Comportement indéfini. Une expression ne peut modifier la valeur d'une variable donnée qu'une seule fois, or ta ligne 2 le fait trois fois. Le résultat est imprévisible.

@uknow : IIRC, les points de séquence sont principalement utilisés pour décrire la sémantique d'un programme C multi-thread. L'idée étant qu'un thread « voit » les effets de bord d'un autre seulement après que l'autre ait passé un point de séquence.

@Mewtwo : je comprends ton idée. Cependant, pour moi, présenter les algorithmes pour les algorithmes me paraît un peu trop abstrait. D'un autre côté, je n'aime pas l'idée de faire un cours sur le langage C qui présente les concepts les uns après les autres, sans jamais les mettre en pratique (ou alors avec des mini-TP). Il me paraît convenable de faire, de temps en temps, un big-TP sur 3 ou 4 chapitres, qui présente un algo avancé tout en montrant comment le mettre en pratique avec le langage C. C'est effectivement un peu bâtard comme approche, mais ça permet de faire de la programmation « grandeur nature ».

+1 -0

Coucou,

J'ai à peu près tout lu ce qui précède (à part les deux dernières pages, je suis fatigué et c'est un peu compliqué pour ce que j'ai à dire), et je voudrais donner mon avis :

Je ne connais rien au C. Je ne m'y suis jamais "mis", pour la bonne et simple raison que ma référence du temps où j'apprenais à programmer était le feu SdZ ; or, ayant commencé par PHP puis Python (je simplifie, pas la peine de détailler mon CV), je n'ai jamais eu le courage d'aborder le big-tuto C qui REpartait de zéro. Pour quelqu'un comme moi (qui ai maintenant un début de connaissances assez éclectiques en informatique et me destine à l'info dans mon avenir professionnel, quoi que plutôt à un niveau théorique a priori), un cours tel que celui vers lequel ce topic semble tendre serait idéal.

A savoir, un cours (ou des cours) partant d'un niveau solide en algo/programmation et explorant les spécificités et concepts un peu poussés que permet d'aborder le langage C, avec des TPs comme ceux proposés quelques pages en arrière, permettant de s'attaquer à des choses que visiblement (si j'ai bien compris la discussion) il vaut mieux aborder avec ce langage et ses spécificités. Un tel cours existe peut-être déjà sur la toile, mais il serait à mon sens un grande plus-value pour ce site s'il était bien rédigé ; et ce en parallèle de (d'un ?) cours destiné(s) à apprendre la programmation. Et sur ce dernier point, je rejoins l'idée que le choix d'un langage en particulier, tel que Python par exemple, est le plus pertinent ; mais ce n'est pas le propos direct du topic et je ne voudrais pas provoquer une énième digression.

Bref, voilà, si un tuto à la fois éclectique et un peu poussé sur le C, et pas avec une approche débutant, venait à naître, il me réconcilierait probablement avec ce langage.

Sur ce, bonne nuit ! :)

+1 -0

@Alkareth: En réalité, il n'y a aucune raison de se forcer à apprendre le C aujourd'hui, comme ça a déjà été dit c'est un peu un langage désuet. Pas la peine de t'y « mettre » de force ou de chercher à te « réconcilier », il y a probablement plus intéressant à étudier pour toi.

Là où je me sens le plus à l'aise en C, c'est en gros l'interface avec l'assembleur. Donc un peu la gestion de la mémoire, comment fonctionne les pointeurs ? Qu'est-ce qu'un cadre de pile par exemple où voir les problèmes d'ambiguïtés du language du genre :

Qu'affiche printf ?

1
2
3
i = 2;
i = (i++)*(i++);
printf("i : \n", i);

Je ne sais pas si ça se recoupe avec ce que voulais faire GuilOoo dans sa gestion de la mémoire. Et je préférerai ne pas écrire ce tutoriel seul, notamment car on est pas à l'abri d'erreurs, et il y a toujours plein de subtilités dans ce domaine.

Saroupille

En l'occurence printf affiche :p

1
i : 

ok, je sors …

+1 -0

@Alkareth: En réalité, il n'y a aucune raison de se forcer à apprendre le C aujourd'hui, comme ça a déjà été dit c'est un peu un langage désuet. Pas la peine de t'y « mettre » de force ou de chercher à te « réconcilier », il y a probablement plus intéressant à étudier pour toi.

FrizaSalikoko

Amen.

D'ailleurs, un autre avantage de l'approche que je défends (montrer des algos avancés en lien avec le bas niveau, et les implémenter en C pour pratiquer) est de montrer dans quels domaines le C est encore utile aujourd'hui. Dans l'autre sens, ça permettra de faire comprendre aux gens qui veulent étudier le C « parce que c'est incontournable » que ça ne l'est probablement pas tant que ça pour leurs domaines respectifs. Au bout de 3 tutos sur les différentes mémoires, les conventions d'appel etc., ils se rendront vite compte si le C est fait pour eux ou non.

EDIT : je ne veux pas en faire un cours élitiste, hein. J'ai bien l'intention de tout expliquer de façon très claire et pédagogue. Je parle simplement d'orienter les exemples et les exercices du cours vers des applications assez bas niveau, pour bien faire passer le message qu'il n'est pas forcément la peine d'étudier le C pour faire des sites Web.

@ Les autres : cherchez pas, ce code n'a pas de sémantique définie. Il pourrait faire n'importe quoi selon l'humeur du compilateur, et vous pourriez lui imaginer mille et une significations. Aucune n'est la bonne.

+0 -0

D'abord la multiplication (2 * 2) = 4 et ensuite la post-incrémentation fois deux. i vaut 6.

Testé sous… gcc.

Mais je m'en remets à l'avis de GuilOooo, ça reste sans doute un comportement indéterminé. En tout cas je n'irai jamais écrire ce genre de chose dans mon code. :o)

Si tu veux vraiment t'amuser, essaie avec différents niveaux d'optimisation, avec différents compilateurs sur différentes architectures… Et si tu n'arrives vraiment pas à faire émerger un comportement tordu, essaie d'écrire ce genre de lignes dans un programme multi-threadé avec un compilateur/archi un peu exotique. Enjoy.

Par contre, on devrait splitter et faire un topic à part pour jouer avec les UB en C.

EDIT : un indice : essaie de déclarer i volatile avec un setup de compilation exotique. Ça devrait déjà donner des résultats rigolos.

+0 -0

D'abord la multiplication (2 * 2) = 4 et ensuite la post-incrémentation fois deux. i vaut 6.

Tiens c'est marrant moi aussi je suis arrivé à 6 mais pas comme ça.

Pour moi le premier i++ est interprété. Du coup sa valeur vaut 2 pour le reste du calcul mais le i est passé à 3. Du coup, le deuxième i++ renvoi 3 et fait passer i à 4. Enfin il y a la multiplication qui est donc 2*3 et génère un 6 dans i qui écrase la valeur précédente.

Ça fait déjà deux interprétations possible du même calcul…

c'est un peu un langage désuet.

Il ne l'est pas dans beaucoup de domaines et de cas d'application.

Ça fait déjà deux interprétations possible du même calcul…

Avec cette expression les effets de bord sont déterminants pour le résultat en sortie de l'instruction, et avec un calcul mathématique simple on dénombre 3 valeurs avec 4 effets de bord en lecture et en écriture sur le même objet donc les valeurs possibles risquent d'être, en nombre, beaucoup plus que ça.

+0 -0

D'abord la multiplication (2 * 2) = 4 et ensuite la post-incrémentation fois deux. i vaut 6.

Tiens c'est marrant moi aussi je suis arrivé à 6 mais pas comme ça.

Pour moi le premier i++ est interprété. Du coup sa valeur vaut 2 pour le reste du calcul mais le i est passé à 3. Du coup, le deuxième i++ renvoi 3 et fait passer i à 4. Enfin il y a la multiplication qui est donc 2*3 et génère un 6 dans i qui écrase la valeur précédente.

Ça fait déjà deux interprétations possible du même calcul…

Kje

Si la multiplication intervient après, ça ferait 4*4, soit 16, non ?

@GuilOooo : avec un volatile, i vaut… 3. Et le code généré fait un peu n'importe quoi… J'abandonne ! :D

Saroupille : Je ne sais même pas de quoi tu parles. Pour moi ça fait parti des nombreux cas où le C à une sémantique ambiguë. Il faut faire un choix sur l'évaluation des expressions.

Est-ce que tu sais à présent ? ;) .

Vu ta phrase tu pensais peut être à un cas du genre :

1
2
i = 2;
printf("%d - %d\n" , i , ++i );

Manque de bol (de connaissances?) tu es tombé sur une expression indéfinie.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte