Salut,
J'ai profité de mes vacances pour rédiger un petit article sur la lecture des déclarations complexes (dans le sens "obscures") en C. Ces "monstres" comme celui du titre, ne sont pas forcément fréquents, mais il peut-être utile de savoir les lire et de manière symétrique de pouvoir les construire.
Un petit rappel des déclarations est proposé autour de quelques éléments clés :
- déclaration vs définition,
- décomposition d'une déclaration : storage class, type qualifier, type specifier, declarator
- les opérateurs légaux dans une déclaration (
*, [], ()
) et les précédences
Finalement, une méthode de lecture simple et facile à retenir est présentée. Cette méthode permet d'attaquer toutes les déclarations, aussi complexes soient-elles . Références et outils (cdecl
!) concluent l'article.
Il s'agissait aussi pour moi de tester AsciiDoc (via AsciiDoctor) qui est une espèce de super Markdown et dont je ne pourrai plus me passer maintenant :-) Je ne sais pas si quelqu'un a fait une dépêche ou un journal sur AsciiDoctor d'ailleurs ? Quoiqu'il en soit, l'article est sous licence CC-by-sa. S'il peut-être utile à quelqu'un j'aurai gagné ma journée !
# J'ai plussé
Posté par Altor . Évalué à -1.
Même si je n'ai rien compris (je ne connais pas le c ni même la programmation), j'ai plussé le journal parce qu'il parle de technique et que c'est quand même rare.
# ...
Posté par M . Évalué à 10. Dernière modification le 13 septembre 2014 à 15:10.
Sympa comme article.
Par contre pour étoffer tu aurais pu aborder l'opérateur ','.
int* i,j;
'j' est il un entier ou un pointeur d'entier ?
Il y a aussi des subtilité avec le const.
'const char *p' vs 'char * const p'.
[^] # Re: ...
Posté par Jehan (site web personnel, Mastodon) . Évalué à 10. Dernière modification le 13 septembre 2014 à 15:47.
Je sais pas si c'est une vraie question ou rhétorique (histoire de signaler un cas où la syntaxe est en effet peu claire), mais au cas où, je vais y répondre. :-)
i
est un pointeur sur entier,j
est un entier. C'est je pense la raison pour laquelle beaucoup de projets vont plutôt écrire l'étoile à côté de la variable, non à côté du type, pour qu'on voit bien à quelle variable cela s'associe:Enfin si tu voulais avoir 2 pointeurs, tu écrirais:
Note que je n'écris dorénavant plus jamais de déclaration de cette sorte, car je trouve en effet cela abscons, et je me posais aussi la question à une époque (jusqu'à ce qu'un jour, je teste). Maintenant je déclare une variable par ligne, même si c'est le même type. Je trouve cela plus clair de cette façons. Au moins, plus de question. :-)
Ça a l'air d'un cas différent, mais c'est en fait très similaire à ce que tu as au dessus (en gros), c'est à dire que tu dois associer le '*' avec ce qu'il y a après.
const char *p
-> tu as d'un côtéconst char
, de l'autrep
. Donc ça signifie que p est un pointeur sur const char. Le pointeur lui-même n'est pas constant (tu peux changer la valeur dep
autant que tu veux). Mais la valeur pointée parp
elle ne peut pas changer (tu peux cependant faire repointer vers une autre valeur différente, ce qui a un résultat similaire).char * const p
-> d'un côtéchar
, de l'autreconst p
. Cela signifie donc que p est un pointeur sur un char (variable). Tu peux changer cette valeur pointée (le char) autant que tu veux, par contre, tu ne peux plus jamais changer le pointeur p lui-même après son initialisation.C'est compliqué, mais faut s'y retrouver avec des associations de ce genre.
Film d'animation libre en CC by-sa/Art Libre, fait avec GIMP et autre logiciels libres: ZeMarmot [ http://film.zemarmot.net ]
# C
Posté par tfeserver tfe (site web personnel) . Évalué à 7.
Très bon article, merci. Ça donnerait presque envie de recoder en C :)
[^] # Re: C
Posté par David Carlier . Évalué à 4.
Pourquoi presque ? :P
[^] # Re: C
Posté par abgech . Évalué à 10.
Moi,cela me donne envie de continuer à programmer en C !
[^] # Re: C
Posté par reynum (site web personnel) . Évalué à 6.
Le C, c'est la vie :-D
kentoc'h mervel eget bezan saotred
[^] # Re: C
Posté par Babelouest (site web personnel) . Évalué à 6.
Comme le disais à peu près je_sais_plus_qui :
[^] # Re: C
Posté par navaati . Évalué à 2.
C'est pas Benjamin Franklin ?
[^] # Re: C
Posté par Babelouest (site web personnel) . Évalué à 3.
Nan je pense pas, lui il codait en Ada, mais il captait rien au C…
# lecture oui, écriture non
Posté par Didier (site web personnel) . Évalué à 10.
Non, définitivement non. Il est nécessaire de savoir les lire (dans le mauvais code des autres), mais il n'est pas utile de savoir les construire (dans son propre code). Même si on les maîtrise soi-même, on ne peut être sûr des capacités des futurs relecteurs du code en question (on peut souvent s'inclure soi-même dans la liste des futurs relecteurs 6 mois après). Il vaut bien mieux 5 lignes de code simples que 1 ligne super compliquée.
Pour la lecture de telles expressions et pour en écrire à titre éducatif ou ludique, ta doc semble très intéressante. Merci pour le temps passé à la rédiger.
[^] # Re: lecture oui, écriture non
Posté par Graveen . Évalué à 5.
Je suis bien d'accord :)
J'imagine que certains pourraient vouloir s'en servir pour obfusquer leur code, mais comme le compilateur traite ca, ca n'a aucun impact sur le fichier généré.
[^] # Re: lecture oui, écriture non
Posté par Zylabon . Évalué à 6. Dernière modification le 13 septembre 2014 à 20:48.
Le C autorise la définition de fonction d'ordre supérieur, c'est très précieux.
Ça dépend par quoi tu accepte de remplacer la ligne compliquée.
Je vais prendre l'exemple canonique,
signal.h
, qui défini une fonctionsignal
, qui prend en paramètre un entier (le signal) et une fonction (qui prend un entier et retourne rien) et qui retourne la précédente fonction associée à ce signal.S'il s'agit de remplacer cette ligne compliquée par
Alors non, pas d'accord, il faut une ligne compliquée.
Mais, strictement équivalent (que l'on trouve dans certaine libc) :
Là d'accord, c'est beau, c'est ce qu'on veut faire, et il faut savoir le faire.
AJOUT : Z'avez vu la colorisation du C du site bug avec le type de signal, faut faire le rapport de bug où ?
Please do not feed the trolls
[^] # Re: lecture oui, écriture non
Posté par Pierre Roc . Évalué à 3.
Pourquoi supérieure ? C’est une fonction. Point. Une fonction qui a pour ensemble de départ un ensemble constitué de fonctions.
Pierre, défendeur de l’égalitarisme fonctionnel, pourfendeur des mathématiques réactionnaires, matraqueur des isomorphismes.
(Une petite larme pour ces millions de x malmenés tant et tant de fois par ces mathématiciens véreux.)
[^] # Re: lecture oui, écriture non
Posté par Zylabon . Évalué à 7. Dernière modification le 13 septembre 2014 à 22:17.
Supérieur, c'est pas méchant, mes excuses aux fonctions se sentant offensées.
Les fonctions du premier ordre jouissent de propriétés que leurs envies beaucoup de leur sœurs d'ordre supérieur. Par exemple le fait de pouvoir vérifier que leur paramètres sont correctes, pour une fonction d'ordre supérieur c'est indécidable.
Please do not feed the trolls
[^] # Re: lecture oui, écriture non
Posté par Graveen . Évalué à 2.
Je ne vois pas où tu veux en venir…
D'une part, ta fonction complexe me parait aussi acceptable (le degré de complexité est modéré);
d'autre part, tu exposes un cas élégant, qui pique moins les yeux.
Donc quel est ton propos ? Qu'il est possible d'avoir un équivalent lisible en connaissant le language ? ;)
[^] # Commentaire supprimé
Posté par Anonyme . Évalué à 7. Dernière modification le 14 septembre 2014 à 13:19.
Ce commentaire a été supprimé par l’équipe de modération.
[^] # Commentaire supprimé
Posté par Anonyme . Évalué à 4. Dernière modification le 14 septembre 2014 à 15:43.
Ce commentaire a été supprimé par l’équipe de modération.
[^] # Re: lecture oui, écriture non
Posté par Zylabon . Évalué à 3.
D'après wikipedia :
Un langage n'a pas besoin d'implémenter les fonctions comme citoyen de première classe pour implémenter des fonction d'ordre supérieur.
Pour l'histoire des pointeurs de fonctions, c'est juste une question d'implémentation, ça ne diminue pas la puissance du langage. Avec le même type d'argument, on affirme que lisp ne permet pas de définir de fonctions. La preuve :
Please do not feed the trolls
[^] # Commentaire supprimé
Posté par Anonyme . Évalué à 3.
Ce commentaire a été supprimé par l’équipe de modération.
[^] # Re: lecture oui, écriture non
Posté par Zylabon . Évalué à 3.
Pourquoi ? Personne n'a jamais dit qu'il était possible d'implémenter toutes les fonction d'ordre supérieur en C (surtout pas moi, comme tu (?) l'a très justement fait remarqué plus haut, il n'y a pas de fermetures en C.
Le C permet d'implémenter des fonctions, Le C permet de passer ces fonctions implémentés à d'autres fonction.
Voilà un programme haskell qui implémente une fonction d'ordre supérieur :
Voilà un programme C, strictement équivalent au programme haskell ci dessus :
Par quel miracle celui ci n'implémenterait pas de fonction d'ordre supérieur ?
J'arrête de discuter là, la preuve est faite.
Please do not feed the trolls
[^] # Re: lecture oui, écriture non
Posté par jyes . Évalué à 1. Dernière modification le 15 septembre 2014 à 09:09.
C’est encore plus flagrant en Fortran, qui ne propose rien de plus que le C à ce niveau, mais dont la syntaxe cache le passage de pointeur. On a bien des fonctions d’ordre supérieur sans fermeture.
La limitation par rapport aux fonctions citoyens de première classe est que, pour le C ou le Fortran, l’appel à la fonction qui utilise une autre fonction en paramètre n’est valide que tant que son paramètre est défini (on ne quitte pas la portée de sa définition).
Edit: dans la mesure ou l’étoile n’est même pas nécessaire en C, le Fortran ne change rien, le passage de pointeur est discret en C aussi.
[^] # Re: lecture oui, écriture non
Posté par jihele . Évalué à 4.
Il y a une réponse qui me vient instantanément, pour ne pas dire compulsivement, mais je vais tenter d'être plus constructif.
https://linuxfr.org/suivi (il y a un lien en haut de chaque page)
Catégorie, je sais pas. Syntaxe markdown, peut-être. Ou CSS. Il vaut mieux un rapport mal rangé que pas de rapport du tout.
[^] # Re: lecture oui, écriture non
Posté par mota (site web personnel) . Évalué à 1. Dernière modification le 13 septembre 2014 à 23:48.
Je trouve ce propos impertinent.
Je suis d'accord qu'une simplification avec un outil d'abstraction approprié comme typedef améliore à la fois la lecture et l'écriture d'une telle déclaration.
Néanmoins il est primordial pour un bon développeur en C de maîtriser parfaitement les arcanes du typage et de la déclaration propres à ce langage, aussi brouillons et inefficaces soient-ils.
Savoir manipuler des notions abstraites comme les fonctions "d'ordre supérieur" (qui n'en sont pas vraiment en C, pas de first-class citizenship pour nos pauvres fonctions :( ) est nécessaire à une bonne organisation d'un code complexe.
On ne peut pas juger de la qualité du code par la complexité de déclaration des typles employés. On a affaire ici à des objets relativement simples à manipuler, qui s'expriment beaucoup plus facilement dans un langage de plus haut niveau.
On pourrait à la limite se permettre de critiquer le langage pour son inexpressivité (qui peut être contournée, cf: typedef), mais pas l'utilisateur.
Étant assistant professeur en C et C++, je préfère largement voir une déclaration complexe sous cette forme de la part d'un de mes élèves, qu'une décomposition en types de données intermédiaires (et les actions associées pour dégager le niveau d'indirection induit) qui ajoutent un overhead. Ça montre que l'élève à compris le typage du langage et le maîtrise. À moi d'être alerte pour reconnaître rapidement le type utilisé.
[^] # Re: lecture oui, écriture non
Posté par Didier (site web personnel) . Évalué à 7.
Je te rejoins : à titre éducatif, c'est intéressant. En revanche, pour du vrai code qui sera relu par d'autres, c'est contre-productif. Dans le monde opensource ou en entreprise, tout le monde n'est pas un crack en C et il faut en tenir compte.
[^] # Re: lecture oui, écriture non
Posté par Graveen . Évalué à 10.
Le propos, c'est que l'écriture de cette forme complexifie inutilement la maintenabilité. Mais c'est peut-être une notion totalement ignorée par les organismes de formation, ceci expliquant pas mal de choses ? :) :)
Soyons clair, on peut toujours trouver un intérêt à une chose (pédagogique, voire obscurantiste), mais en gardant un peu raison, on peut aussi s'apercevoir de sa vacuité dans 99% des cas.
# Ton exemple 3
Posté par esdeem . Évalué à 8. Dernière modification le 14 septembre 2014 à 18:40.
Sur ton exemple 3, tu as dans la 5e boîte ceci :
extern int (*x[42])(int);
________^^^^^
x est un tableau de 42 pointeurs vers DES FONCTIONS QUI RETOURNENT ...
C'est pas plutôt
x est un tableau de 42 pointeurs vers DES FONCTIONS PRENANT UN "int" ET QUI RETOURNENT ...
ou j'ai raté quelque chose ?P.-S.
Désolé, le formatage part aux fraises…
0. Assume good faith 1. Be kind to other people 2. Express yourself 4. Apply rule 0
[^] # Re: Ton exemple 3
Posté par dcp . Évalué à 3.
C'est chouette d'avoir de relecteurs :-)
Merci, c'est corrigé (remarque, la traduction était imprécise, mais pas fausse !)
# Espaces de noms
Posté par Michaël (site web personnel) . Évalué à 4.
Bravo pour ton article, au sujet duquel j'ai deux remarques à faire:
Tu ne parles pas des espaces de noms des diverses structures. De mémoire on peut définir différemment
struct my_struct
ettypedef struct { } my_struct
parceque dans les deux casmy_struct
appartient à des espaces de noms différents. C'est un point technique qui est bien dans le sujet de ton article — mais comme je ne programme plus en C depuis longtemps je ne connais plus ces détails par cœur.Tu ne parles pas du petit programme qui permet de traduire les définitions de pointeurs en anglais, c'est un exercice du K&R qui aurait toute sa place dans ton article!
[^] # Re: Espaces de noms
Posté par grim7reaper . Évalué à 2.
Tu veux dire qu’il n’en parle pas comme dans cette phrase dans la section « Liens divers » :
[^] # Re: Espaces de noms
Posté par Michaël (site web personnel) . Évalué à 3.
Au temps pour moi!
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.