Obsidian a écrit 5299 commentaires

  • [^] # Re: C'est dd qui merde

    Posté par  . En réponse au message cat et dd. Évalué à 4.

    Les pipes sont bien bloquants… s'il n'y a rien à lire dedans ! Mais si on fait un appel read() dessus en passant la taille d'un buffer par exemple et qu'il y a bien des caractères disponibles mais qu'il n'y a pas le compte, alors l'appel va ressortir en renvoyant le nombre de caractères qu'il a réussi à lire.

    Lorsqu'on exploite directement le disque ou un fichier, la question ne se pose pas. Les caractères sont forcément disponibles et c'est directement dd (ou n'importe quel programme à sa place) qui va aller chercher les données, par l'intermédiaire du pilote. Il n'y a qu'en cas de fin de fichier ou d'erreur que le bloc à lire peut être incomplet.

    Par contre, dans le cas d'un pipe, c'est entièrement au bon vouloir du processus écrivain qui, par définition, a un comportement asynchrone et versatile.

  • [^] # Re: À vue de nez…

    Posté par  . En réponse au message cat et dd. Évalué à 1.

    Je retire le point numéro 2. J'ai confondu « seek » et « skip ».

  • # À vue de nez…

    Posté par  . En réponse au message cat et dd. Évalué à 3.

    1. Pourquoi utilises-tu trois « cat » successifs dans un bloc ? « cat » signifie « catenate » et sert justement à concaténer plusieurs fichiers. Utilise plutôt « cat fichier1 fichier2 fichier3 » et vire les parenthèses ;

    2. Si tu lis tes données depuis l'entrée standard, il faut enlever les clauses « seek ». Tu ne relis pas, à chaque fois, le même fichier depuis le début, tu lis les données qui te parviennent les unes après les autres. Le début de ton fichier a donc déjà été « consommé » par les commandes « dd » précédentes.

  • [^] # Re: L'hôpital se fout de la charité…

    Posté par  . En réponse au message Alternative fiable à Firefox sous Windows. Évalué à 2.

    Question bête : qu'est-ce que tu utilises pour accéder à tes serveur Unix ? J'imagine que c'est déjà le cas mais, autrement, un serveur X pour accéder à une session XDMCP ne serait-elle pas la solution pour avoir la paix ?

    Il fut un temps, dans un métier antérieur, où l'on n'utilisait que des thin clients pour se connecter à des serveurs de travail, lesquels étaient sous Windows, sous Solaris ou sous Linux. Bien que ceux-ci reconnaissent les principaux protocoles de tous les serveurs, il était parfois plus efficace de se connecter à un Linux et d'y ouvrir un rdesktop vers les serveurs Windows. Malgré les relais successifs, c'était plus fluide :-)

  • [^] # Re: L'hôpital se fout de la charité…

    Posté par  . En réponse au message Alternative fiable à Firefox sous Windows. Évalué à 2.

    Je n'ai qu'un mot : pauvre abruti.

    Reconnais que ça ne donne pas vraiment envie de t'aider (et qu'en plus, ça fait deux mots).

    Alors c'est vrai, tu me répondras que j'ai choisi mon taf, mais d'un autre côté, l'OS que j'utilise au quotidien pour accéder à mon environnement de travail n'est pas le plus important dans mon travail. Et mon poste actuel me permettra de gagner en compétences et en crédibilité, pour pouvoir à l'avenir je l'espère, me passer d'un environnement windows pour effectuer mes taches quotidiennes.

    J'espère simplement que tu t'épanouis dans ton poste sur d'autres points ou qu'à tout le moins, tu y trouves ton compte. Parce qu'autrement, je ne sais pas où tu habites, mais les postes sous Linux sont quand même beaucoup plus courants qu'on ne le croit. Là où je travaille, on m'a filé un poste vide et on m'a laissé le choix de l'O.S. (Windows compris, avec licence). J'y ai mis une Fedora 15.

    C'est très bien d'essayer de faire carrière et de trimer dur pour espérer aboutir à la situation qui te plaît, mais l'expérience m'a montré que 1) la vie est courte ; 2) la carrière l'est encore plus ; 3) Personne ne va t'orienter à ta place si tu ne pèses pas de toute ta personne pour aller où tu veux. Bouffer des technos que l'on n'aime pas, c'est bien quand c'est alimentaire. Pour le reste, il est si rare d'avoir des opportunités dan le monde du travail que c'est presque criminel de ne pas en profiter quand elles se présentent. :-)

    Le piège absolu quand on est orienté Linux étant les S.S.I.I. Quand on a passé deux ans à se faire dire telle mission est sous NT4 (à l'époque) mais que la prochaine sera sous Unix, garanti ! et qu'on a fait ça sept fois de suite, on comprend vite que ces compagnies ne se font pas d'argent avec des systèmes qui fonctionnent.

  • # Opera

    Posté par  . En réponse au message Alternative fiable à Firefox sous Windows. Évalué à 1.

    Opera

    http://www.opera.com/

    Fonctionne aussi bien sous Windows que sous Linux. Si tu ne connais pas déjà, si tu ne peux utiliser Firefox et qu'il n'est évidemment pas question de repasser à I.E., je pense que tu seras vite « Konqui » :-)

  • [^] # Re: Merci beaucoup à vous, j'ai tout compris !

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

    //cool qu'on puisse dé-référencer sans étoile

    Oui, et si c'est le cas, ça fonctionne aussi dans l'autre sens. Ces deux expressions sont équivalentes s'il s'agit d'une fonction :

    ptr_g = &g;
    ptr_g = g;
    
    

    J'ai toujours un avertissement que je ne comprend pas, concernant la ligne return a(); :
    attention : ‘return’ with a value, in function returning void [enabled by default]
    a() ne retourne pas void puis-ce qu'il est de type int (*) (void)…

    Non, mais ta fonction main(), elle, est déclarée « void main (void) ». Ce qui gène alors le compilo, c'est justement le fait que tu renvoies un int.

  • # Grammaire C

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

    Je rajoute un commentaire pour préciser que la norme C spécifie et détaille la grammaire formelle du langage (tant et si bien qu'en théorie, on pourrait presque la balancer directement à Lex & Yacc pour recompiler un compilateur, ce qui est précisément la définition de « Y.A.C.C. »).

    Et en ce qui concerne les types en particulier, ceux-ci font l'objet d'une section dédiée : 6.7.6

    6.7.6 Type names
    
    type-name:
        specifier-qualifier-list abstract-declaratoropt
    abstract-declarator:
         pointer
         pointeropt direct-abstract-declarator
    direct-abstract-declarator:
        ( abstract-declarator )
        direct-abstract-declaratoropt [ type-qualifier-listopt assignment-expressionopt ]
        direct-abstract-declaratoropt [ static type-qualifier-listopt assignment-expression ]
        direct-abstract-declaratoropt [ type-qualifier-list static assignment-expression ]
        direct-abstract-declaratoropt [ * ]
        direct-abstract-declaratoropt ( parameter-type-listopt )
    
    

    Les « opt » en fin de noms de règles sont en fait écrits en indice dans le document PDF. Donc, ici, « pointer » et « pointeropt » sont la même règle.

    On voit, comme c'est l'usage dans la définition de telles grammaires, que les différentes règles font massivement références à elles-mêmes, d'où la récursivité. C'est ce qui te permet de construire des types de plus en plus compliqués, en partant du centre comme expliqué dans nos commentaires précédents.

  • [^] # 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.