Obsidian a écrit 5291 commentaires

  • [^] # Re: Parsing en C

    Posté par  . En réponse au message L'opérateur unaire * me laisse perplexe (pointeurs sur fonctions principalement). Évalué à 2.

    Hello,

    Cependant, il y a encore des choses qui m'échappent. Tu dis « Tu poses (éventuellement) un >identifiant »
    Ne pas mettre l'identifiant sert à donner le type de retours d'une fonction par exemple ?
    dans l'exemple
    int f(int)(void);

    C'est un exemple qui ne fonctionnera pas. Le compilo ne te laissera pas faire. Par contre, il te dira quand même « erreur: ‘f’ declared as function returning a function », ce qui montre que notre syntaxe était correcte sur le plan formel.

    on peut dire que le retour de f est de type int (void) ? Par exemple, imaginons une fonction qui retourne un pointeur vers une fonction int (g)(void) mais sous forme d'un pointeur (void *) comme le ferait un thread par exemple, il est possible de caster ce pointeur avec ( int ()(void) ) ?

    N'oublie pas que tu retournes un pointeur ! Il faut donc le caster vers un « pointeur sur une fonction n'admettant aucun argument, mais retournant un int ». Donc « (int(*)(void)) ». Ça, oui, c'est possible. Tu peux même l'invoquer directement en ajoutant des paramètres entre parenthèses à la suite de ton appel à « f », ce qui donne une syntaxe toute particulière. :-)

    Je trouve que les pointeurs vers des fonctions font 4 octets (quelle qu'elles soient), et que les fonctions n'en font qu'un (d'ailleurs, on est limité à 256 types de fonctions ?)

    Il est probable (c'est à vérifier) que dans ce cas précis, le compilateur utilise un mécanisme similaire aux énumérations pour cataloguer tes définitions de type de fonction. Ces énumérations sont réputées être codé sur un type entier de n'importe quelle taille (donc y compris char). Les membres eux-mêmes devant pouvoir être convertis en int.

    j'ai l'impression d'être complètement à coté de la plaque. Je crois qu'il faut vraiment que j'apprenne des bases d'assembleur.

    C'est toujours une bonne chose de le faire, et ça t'aidera beaucoup dans la compréhension du C et des systèmes informatiques en général. Par contre, dans ce cas précis, ça ne te sera d'aucune utilité.

  • [^] # Re: Parsing en C

    Posté par  . En réponse au message L'opérateur unaire * me laisse perplexe (pointeurs sur fonctions principalement). Évalué à 2.

    UPDATE: J'ai des crochets qui ont disparu dans la déclaration de « tableau ». Je la refais :

    1. tableau
    2. tableau[]
    3. (* tableau[])
    4. (* tableau[])()
    5. int (* tableau[])()
  • # Parsing en C

    Posté par  . En réponse au message L'opérateur unaire * me laisse perplexe (pointeurs sur fonctions principalement). Évalué à 4.

    là, l'opérateur s'applique à ce qu'il y a à sa droite :
    int * ptr_sur_entier,entier; // déclare un pointeur sur int, et un int, donc c'est équivalent à :
    int (*ptr_sur_entier),entier;

    En fait, ça s'applique bien à gauche mais… une seule fois. :-) C'est dû au fait que contrairement aux autres spécificateurs de type, tu peux enchaîner les pointeurs sur une longueur arbitraire. Ainsi :

    typedef char *** montype;
    montype **a, *b;

    … te donnera respectivement « char ***** a » et « char **** b ». L'opérateur « * » sert donc bien à définir un type, mais est un non-terminal.

    Pour le reste, tout devient plus clair lorsque l'on admet qu'un type est défini de manière récursive, comme lorsque tu développes une expression mathématique en commençant par les parenthèses les plus imbriquées, celles-ci pouvant se trouver au centre de l'expression et pas forcément sur les côtés.

    Un type en lui-même pourrait être défini de n'importe quelle manière mais que, dans les faits, il se trouve généralement à gauche de l'identifiant auquel il est ÉVENTUELLEMENT associé, sauf dans deux cas : les déclarations de fonctions et les déclarations de tableaux, qui se représentent respectivement avec () et [], lesquels prennent place à droite de l'identifiant. Donc, dans l'ordre :

    1. Tu poses (éventuellement) un identifiant. Le nom de ton instance ;
    2. Tu le fais suivre au choix par

    — Rien (instance ordinaire)
    — Une paire de parenthèses (fonction), à l'intérieur desquelles tu vas parser… des noms de types éventuellement nommés (les paramètres), exactement comme tu es actuellement en train de le faire. Récursivement, donc.
    — Une paire de crochets (tableau) contenant une taille éventuelle.

    1. Tu fais précéder soit par rien, soit par une une étoile pour indiquer que l'expression ENTIÈRE décrite jusqu'ici est un pointeur et non l'élément final ;
    2. Tu qualifies enfin cette expression entière en lui donnant son type propre, pour qu'elle puisse finalement être évaluée et ce, soit avec un nom de type terminal en toutes lettres, à gauche, soit en reprenant au point numéro 2 !

    Et comme le point numéro 2 est prioritaire par rapport au n° 3 et au n°4, tu peux utiliser des parenthèses dans la construction de ton expression pour forcer la priorité.

    Ainsi, une fonction admettant un int en entrée et te renvoyant un pointeur de fonction acceptant deux float et renvoyant un double se construirait ainsi :

    — « fnct » le nom de mon instance ;
    — « fnct(int) » suivie des parenthèses avec des types à l'intérieur : fonction ;
    — « * fnct(int) » précédée d'une étoile : l'expression entière est de type pointeur. Note que la priorité de 2. sur 3. fait que c'est ma « fonction qui est de pointeur » et non mon « pointeur qui pointe une fonction » ;
    — « (* fnct(int)) » ici, je suis obligé d'ajouter des parenthèses, sinon ce que je rajouterais à droite serait prioritaire sur mon pointeur. Mon expression est donc une fonction de type pointeur sur quelque chose. Mais quoi ?
    — « (* fnct(int))(float,float) » … sur une fonction, impliquée par mes parenthèses. Cette fonction attend donc deux _float ;
    — « double (* fnct(int))(float,float) » cette fonction est une expression mathématique qui peut être évaluée. Comme elle renvoie un double, je peux placer mon terminal « double » à gauche. Mais si elle renvoyait quelque chose de plus évolué, je pourrais très bien repartir pour un tour.

    À noter ainsi que je pourrais très bien faire une fonction qui renvoie non pas un pointeur de fonction mais… une autre fonction ! Syntaxiquement, ce serait possible. Exemple : une fonction « f » qui admettrait un int et renverrait une fonction de type « int g (void) » s'écrirait :

    int f(int)(void);

    En soi, ce serait un bon moyen d'implémenter les lambdas-fonctions. Bon, en fait, cela ne pourrait pas être écrit directement de cette façon car cela impliquerait que l'on puisse instancier plusieurs fois la même fonction. Mais le C++11 a quand même introduit une syntaxe pour le faire…

    L'opérateur de transtypage, maintenant, admet tout simplement un type, sans identifiant, entre une paire de parenthèses. Il faut donc simplement résoudre ce qui se trouve à l'intérieur sans se soucier de ce à quoi on l'applique, aller au bout de la procédure, et seulement ensuite examiner ce qui suit.

    à quoi ressemble un tableau de pointeur sur fonctions qui retournent un int en mémoire ?

    1. tableau
    2. tableau[]
    3. (* tableau)
    4. (* tableau)()
    5. int (* tableau)()

    est-ce que les argument des fonctions de ce tableau changent sa représentation ?

    Ça ne change pas la manière de les construire. Par contre, quand tu définis ce type, tu déclares dans la foulée les fonctions qu'il pointe. Il est donc nécessaire d'établir proprement leur signature, pour que le programme qui déréférence le pointeur puisse utiliser les fonctions qui sont pointées.

    En outre, il y a une subtilité qui dit qu'en C ISO, fnct() et fnct(void) sont identiques mais qu'en K&R, le premier sert simplement à déclarer l'existence de la fonction sans la décrire plus. Je ne sais pas si cela s'applique sur les définitions de type.

    J'imagine que par ailleurs c'est très dépendant de l’architecture.

    En principe, non. Un code C canonique propre est censé être parfaitement portable.

  • [^] # Re: Pourquoi ?

    Posté par  . En réponse au journal Le respect des licences. Évalué à 4.

    Cela dit, s'il arrivait à les convaincre, on aurait quand même la paix pour un bout de temps…

  • [^] # Re: Oula plein de chose dans le poste

    Posté par  . En réponse au message L'opérateur unaire * me laisse perplexe (pointeurs sur fonctions principalement). Évalué à 3.

    Non, c'est pareil, malloc retourne un void, et donc le compilo gueulerait disant que tu associe un void à ton pointeur de tableau qui est de type pf. Le cast (pf)malloc dis au compilo que tu sait ce que tu fais et que le void* est comme un pf* (on appelle ça transtypage d'une variable).

    Dans ce cas précis, c'est inutile. Le compilateur ne se plaint jamais lorsqu'on affecte un pointeur void vers un pointeur d'un type quelconque et vice-versa. C'est vrai au moins en C99. Ça semble être aussi le cas en C89 mais je ne dispose pas du document correspondant :

    Extrait de n1256

    6.5.4 Cast operators
    1. […]
    2. […]
    3. Conversions that involve pointers, other than where permitted by the constraints of
    6.5.16.1, shall be specified by means of an explicit cast.

    6.5.16.1 Simple assignment
    Constraints
    One of the following shall hold:
    — […]
    — […]
    — […]
    — one operand is a pointer to an object or incomplete type and the other is a pointer to a
    qualified or unqualified version of void, and the type pointed to by the left has all
    the qualifiers of the type pointed to by the right;

  • [^] # Re: à l'assaut de Microsoft maintenant !

    Posté par  . En réponse à la dépêche Le standard C++0x a enfin été voté. Évalué à 7.

    Je ne vois pas le rapport (à part le temps que mettra Visual C++11 à respecter entièrement la norme, mais bon…)

  • [^] # Re: proposition lowcost

    Posté par  . En réponse au journal Nom de geek pour une chatte ?. Évalué à 9.

    Voire même lolcathost…

  • # Fichier de log effacé

    Posté par  . En réponse au message Qui mange mon espace disque ?. Évalué à 3.

    Il y a un truc ultra-classique, mais qui fait perdre beaucoup de temps la première fois que ça arrive : le fichier de log que l'on efface pour gagner de la place alors qu'il est encore ouvert par une instance du programme qui le gère.

    C'est très chiant parce que l'on pense avoir libéré la place alors que ce n'est pas le cas, et tous les scans du système de fichier que l'on puisse faire sont sans objet puisque l'entrée n'existe plus.

    Solution : « lsof » avec un regard particulier sur la taille des fichiers concernés. En principe, une fois tué le processus concerné, le fichier se vide de lui-même. À moins bien sûr qu'il existe un lien dur sur ce fichier à un autre endroit de l'arborescence.

  • [^] # Re: Baptême

    Posté par  . En réponse à la dépêche Migration LinuxFr.org terminée. Évalué à 8.

    Dans les « anales », donc.

  • [^] # Re: Experts

    Posté par  . En réponse au journal À quoi servent les fichiers hosts et comment les supprimer sous linux ?. Évalué à 2.

    Et l'édition moléculaire : https://linuxfr.org/users/jpauty/journaux/le-nouveau-concept-r%C3%A9volutionaire-de-jayce-l%C3%A9dition-mol%C3%A9culai

    Personne n'aurait une copie de ce draft d'avant-garde ?

  • [^] # Re: Vraiment génial

    Posté par  . En réponse au journal Transformers 3 : la face cachée de la lune. Évalué à 1.

    La discussion se transforme vite devant la déception du film de la news, c'est automatique!

    Ben, c'est pas pour rien qu'ils s'appellent les décepti-cons.

  • [^] # Re: heu

    Posté par  . En réponse au journal Transformers 3 : la face cachée de la lune. Évalué à 3.

    Parceque le neutrino il est moins con que le photon : pour rejoindre B depuis A, lui il file tout droit. Peu importe des masses à proximité sur son chemin, il s'en bat comme de sa première choisi le neutrino : zzzzzzzzzouuuuuuu il fait. Et regarde le photon, à côté de lui en début de course, en se demandant "mais qu'est ce qu'il a, lui ? il est bourré ou quoi pour marcher tout le temps de travers ?"

    N'empêche que si le neutrino faisait comme le photon et prenait le TGV, il serait déjà arrivé.

  • [^] # Re: Euhh.....

    Posté par  . En réponse au journal Interrogation surprise !. Évalué à 1.

    Ce n'est quand même que moyennement ressemblant…

  • [^] # Re: Tri comptage

    Posté par  . En réponse au journal Une autre excuse pour ne pas bosser…. Évalué à 2.

    Oui mais, comme indiqué dans le fil juste au-dessus, ce n'est pas inhérent à l'algorithme lui-même. Tu peux très bien ranger n réveils sur ton étagère en les programmant en fonction de leur numéro, et ce sans avoir à recourir à un système d'exploitation ni même allumer un ordinateur.

  • [^] # Re: complexité algorithmique

    Posté par  . En réponse au journal Une autre excuse pour ne pas bosser…. Évalué à 2.

    Même pas, parce que pour que cela vaille le coup, il faudrait que l'intervalle entre les timers soit égal à l'overhead nécessaire à leur traitement, qui de toutes façons couvrirait un temps suffisant pour comparer entre eux des dizaines d'éléments. C'est efficace, mais ça reste lent.

    L'intérêt de la chose n'est pas là. D'une part, il suffit que ce soit vrai une fois pour valider l'algorithme. Ensuite, c'est la première fois, à ma connaissance, qu'on exploite la dimension temporelle de manière active pour parvenir à ses fins.

    Et ce qui est vraiment notable, c'est que cet algo, comme ses frères, est complètement transposable dans le monde réel, même si tu éteins ton PC. Il ne repose pas sur un « sous-algorithme ».

    T'en connais beaucoup des algos de tri qui, à la fois, fonctionnent sans comparer les éléments entre eux, ont une complexité en O(n) et sont stables par dessus le marché ?

  • [^] # Re: complexité algorithmique

    Posté par  . En réponse au journal Une autre excuse pour ne pas bosser…. Évalué à 5.

    Ah mais justement, tout est là : l'algo utilisé pour trier les timers sur le système d'exploitation ne peut pas être considéré comme étant sous-jacent au sleep sort.

    Si j'éteins mon ordinateur et si je prends dix minuteurs (pour cuire les œufs, par exemple), que je leur colle tous un numéro et que je veux trier ces minuteurs sur mon étagère, je peux tous les programmer à une durée correspondant à leur numéro respectif (donc en seule fois : complexité linéaire), et prendre chaque minuteur qui sonne pour le ranger à la suite des autres sur mon étagère, ou les mettre les uns sur les autres dans une boîte, ce qui revient à les empiler (donc, exit toute nécessité de conditions d'accès particulières).

    Certes, j'utilise la propriété qu'ont ces minuteurs de pouvoir se signaler eux-même, mais il est de fait que je me retrouve ainsi avec mes dix minuteurs triés, alors qu'à aucun moment, je ne les ai comparés entre eux !

    Et ça, c'est assez remarquable !

  • [^] # Re: Apprentissage

    Posté par  . En réponse à la dépêche Science et éducation : EZ-Draw 1.0 est sorti. Évalué à 1.

    Y a beaucoup de dinos qui disent que tout découle réellement, en pratique, de ALGOL 60. Je n'ai jamais eu l'occasion de vérifier si c'est vrai.

  • [^] # Re: Forcement...

    Posté par  . En réponse au journal Comment refuser la fibre optique. Évalué à 6.

    Ou sinon, t'as la solution plus polie : "désolé, M. Machin est décédé avant-hier. Je dois vous laisser : on nous attend à la morgue". AMHA, ça doit jeter un froid tel qu'ils vont pas rappeler de suite...

    Tu parles ! Ça ne les arrête pas ! Le démarchage par téléphone, c'est exactement la même chose que le spam. Il est établi à la base que c'est dérangeant pour la plupart des gens ciblés, mais il reste l'espoir que les quelques pigeons qui tomberont dedans compenseront la gêne occasionnée. Ceci posé, quand on s'est fait raccrocher au nez cent fois de suite, on considère que les suivants ont toujours l'option de faire la même chose et que, s'ils restent en ligne, c'est qu'ils le souhaitent.

    J'ai perdu mon père il y a trois ans et repris la ligne de téléphone, qui est donc resté un moment à son nom. La ligne n'était pas sur liste orange à ce moment et cela devenait insupportable (jusqu'à cinq appels par jour). Au bout d'un moment je me suis servi du fait que la personne qu'ils appelaient était décédée pour couper court aux conversations. J4ai effectivement eu quelques condoléances mais globalement, c'était :

    « — Bonjour, je suis xxx de la société yyyy…
    — Vous souhaitez parler à M. xxxx ?
    — Oui…
    — Je suis désolé, il est décédé.
    — Ah ? Bien. Puis-je parler au chef de famille, alors ? ».

    Raccrochage immédiat, bien sûr.

    Après deux ou trois conversations du même acabit, j'ai repris les choses en main. Liste orange immédiate qui a eu pour effet d'éliminer 80 % des appels (quand même). Lorsque l'interlocuteur est aimable (et parle français), j'explique poliment mon cas en demandant explicitement à être retiré de leur liste et en m'assurant que ma requête a bien été comprise.

    Après m'être battu contre les vendeurs de fenêtres, et autres… l'une des rares grandes compagnies à me démarcher encore est… SFR.

  • # IGNobel

    Posté par  . En réponse au journal Une autre excuse pour ne pas bosser…. Évalué à 10.

    Je pense que ça mérite au moins au moins le prix Ig nobel, si l'on considère son plus récent objectif, soit récompenser les initiatives qui ont faire rire d'abord puis réfléchir juste après.

    Qu'en pensez-vous ? (On pourrait même dire « Quand pensez-vous ? », ce serait approprié ici).

  • [^] # Re: Bon sens...

    Posté par  . En réponse au journal Énergie nucléaire et bon sens. Évalué à 4.

    Je voulais juste montré comment, avec les tournures adaptées, on peut changer la signification des choses.

    C'est clair. C'est comme ça que certains ont essayé de nous faire croire que le monoxyde de dihydrogène était bon pour la santé… :-)

  • [^] # Re: Allemagne

    Posté par  . En réponse au journal Énergie nucléaire et bon sens. Évalué à 3.

    « Who needs oil ? I ride the bus ! »

  • [^] # Re: Énergie nucléaire et bon sens

    Posté par  . En réponse au journal Énergie nucléaire et bon sens. Évalué à 10.

    Je m'en fous ségolènement de la manière utilisé pour produire notre électricité chérie, mais d'une force dont tu ne peux imaginer la puissance phénoménale

    Ah ben c'est intéressant, ça : penses-tu que l'on puisse utiliser cette force pour produire de l'électricité ? :-)

  • [^] # Re: Salut à toi..

    Posté par  . En réponse à la dépêche Salut à Toi (GNU/)LinuxFr.org !. Évalué à 6.

    L'avantage, c'est que ça se factorise assez facilement…

  • [^] # Re: Real Programmers use Fortran

    Posté par  . En réponse au journal Le problème de la POO pratiquée par des étudiants. Évalué à 2.

  • [^] # Re: Les Fonctions Génériques

    Posté par  . En réponse au journal Le problème de la POO pratiquée par des étudiants. Évalué à 3.

    Je pense que le terme « méthode » ne doit pas avoir la même signification dans les deux langages (de toutes façons, en C++, ce sont des « fonctions membres »).

    Sinon, l'intérêt du template est justement de ne pas avoir à réécrire le code correspondant. Les types génériques dans le code sont remplacés par celui que tu spécifies et, seulement alors, la fonction est compilée dans cette version, ce qui, généralement, produit du code machine complètement différent selon l'objet manipulé alors que l'algorithme reste rigoureusement identique.

    Ensuite, le programmeur peut ensuite écrire lui-même certaines versions de la fonction template pour certains types explicitement. C'est utile, par exemple, si tu fais un container à objet. La plupart du temps, tu stockeras des pointeurs ou des références vers tes (gros) objets. Mais si ce sont des caractères individuels que tu comptes stocker, alors il vaut mieux les enregistrer directement puisque les pointeurs qui les référencent seront entre 4 et 8 fois plus gros que les caractères eux-mêmes.

    Mais les templates ne sont pas liés en eux-mêmes à la surcharge des opérateurs, ni à celle des fonctions membres, d'ailleurs.