benja a écrit 1211 commentaires

  • [^] # E_NOENOUGH_INFO | E_UNNEEDED

    Posté par  . En réponse au message Volatile, struct et interruptions.. Évalué à 2. Dernière modification le 14 janvier 2016 à 22:28.

    Quelques remarques en attendant que tes algos soit spécifiés et que l'on puisse te donner une réponse précise.

    • si ton interruption ne se fait pas interrompre, un volatile dans le code de l'interruption ne sert effectivement à rien.

    • un volatile dans le code "main" peut-être utile mais certainement pas suffisante (enfin faut voir ton algo toujours). Je conjecture que tu auras quand même besoin d'implémenter un mécanisme de type mutex pour te prémunir des problèmes de TOCTOU.

    • inspecte le code assembleur pour être sûr de savoir ce que ton compilo a produit.

    • mettre volatile est souvent une fausse bonne idée. Je te laisse rechercher les références de Linus sur la LKML ;-) La démonstration suit…

    Admettons que ton main ressemble à cela:

    // pseudocode, addresse du buffer assimilée à zéro,,,
    if (tail < head)
      sz = tail + (bufsz - head);  // le buffer a "wrappé"
    else
      sz  = tail - head;
    
    if (sz >= MIN_COPY) {
      copy(head, copy_size); // gère le wrapping
      move_head(&head, copy_size); // idem
    }
    // loop...
    

    Au niveu de l'interruption:

    //calculer sz comme au dessus, puis calculer l'espace libre
    freesz = bufsz - sz;
    
    if (freesz >= neededsz) {
       while (neededsz--) {
          *tail = data; // ??
          if (tail == bufz - 1) // wrap ?
             tail = 0;
          else
             tail++;
       }
    } else {
       *overrun = 1;
    }
    

    NB: c'est une implémentation naïve d'un buffer circulaire. Je n'ai jamais fait ce genre de chose, je te conseille quand même de consulter wikipedia avant ;-)

    Donc nous avons ton interruption qui modifie tail et ton main qui modifie head.

    • Il y a-t-il un risque que l'interruption utilise une mauvaise valeur pour head ? C'est-à-dire entre le momen où tu calcules freesz et le moment où tu modifie tail.
      -> Non je ne crois pas, au pire tu as un overrun du à un freesz sous-estimé.

    • Il y a-t-il un risque que main utilise une mauvaise valeur de tail ? Idem, non je ne crois pas.

    Le problème se situe au moment où l'on calcule sz et freesz !! En fait là tu ne veux surtout pas de volatile : que se passerait-il si tail est accèdée en volatile et qu'une interruption fait wrapper tail et survient juste après que tu aies testé qu'il n'y a pas de wrap ? Oops un freesz < 0… ça sent pas bon hein… ;-)

    Donc bref: tu copies tes volatiles dans des variables locales au début de ta routine pour être certain que tu n'accède pas à tes variables en ram directement. Ton algo doit être conçu pour fonctionner sur des valeurs qui ne reflètent peut-être plus la réalité mais qui son cohérentes entre elles, pas pour fonctionner avec des valeurs certes actuelles mais qui changent au gré du vent/des lignes!!!

    (Ma) conclusion : pas besoin de mutex, surtout pas besoin de volatile, sous réserve que le code "main" soit dans une fonction séparée.

    Maintenant si tu passes à plusieurs producteurs/consommateurs, ben ça se complique : ne le fais pas, utilise plusieurs buffers :p

    PS: je viens de me rendre compte que c'est l'inverse que tu veux faire, soit vider un buffer par une interruption. Cela revient au même.

  • [^] # Re: $(SHELL)

    Posté par  . En réponse au journal Utiliser Python comme interpréteur dans vos Makefile. Évalué à 0.

    Quand on utilise sh avec make, il ne faut pas oublier qu'il y a, pour chaque ligne au moins un fork (sh), c'est toujours le cas ici.

    Non justement, GNUMake exécute SHELL…

    Dès qu'on utilise un sed, awk, des pipes etc, ce sont autant de forks…

    L'idée c'est d'utiliser les fonctions de make pour manipuler le one-liner avec les $(subst …) et autres. https://www.gnu.org/software/make/manual/html_node/Text-Functions.html#Text-Functions

    Sorry de n'avoir pas été super explicite sur ce coup, ce que je voulais dire c'est:
    1) Pourquoi overrider SHELL pour au final lancer un sh pour faire des manipulation de chaînes qui pourraient tout a fait être faites par Make et ce faisant économiser l'exécution superflue d'un sh. Et le corrolaire 2): tant qu'à quand même utiliser sh, pourquoi pas se garder d'overrider SHELL mais utiliser à la place une fonction make $(PYTHON …) afin de pouvoir garder le meilleurs des deux mondes ?

  • [^] # Re: $(SHELL)

    Posté par  . En réponse au journal Utiliser Python comme interpréteur dans vos Makefile. Évalué à 6.

    heu.. mais c'est ce qu'il fait hein ;-)
    Bonjour les perfs par-contre, vu qu'avec cette méthode, toutes les règles utilisent python (+ un shell pour lancer un "wrapper" dont je me demande s'il ne serait pas possible de se passer tout simplement). Pourquoi ne pas écrire une fonction ad-hoc pour GNUMake ? I.e. genre $(PYTHON "mon on-liner").
    Il faut bien se render compte aussi qu'il n'y a pas d'état persistent, donc on ne peut pas manipuler l'état de l'interpréteur dans une règle pour le réutiliser dans une autre. Ça pourrait être amusant d'embedder un deuxième language de script dans make, en Lua cela devrait-être assez facile… (par contre no-comment pour la "maintenabilité").

  • [^] # Re: Windows 2 en base 10?

    Posté par  . En réponse au journal A vos risque et périls . Évalué à 0.

    2 en base 10 ça fait 10 en binaire. Aux dernières nouvelles, on n'a toujours pas retrouvé le 2 en binaire; on a même demandé aux romains, c'est dire…

  • [^] # Re: rtfm

    Posté par  . En réponse au message barre de progression avec nohup.out. Évalué à 0.

    Ah ouais, je comprends mieux du coup :-P
    Merci ;-)

  • [^] # Re: rtfm

    Posté par  . En réponse au message barre de progression avec nohup.out. Évalué à -3.

    Ok c'est de la provoque mais bon j'ai quand même donné par 2 fois la réponse, passé par 2 fois du temps pour rédiger un commentaire et pour chercher la réponse. Qu'apportent les gens qui moinssent ? Si ce n'est de décourager les personnes qui contribuent , elles… Allez bon sang, un peu de pédagogie svp!

  • [^] # Re: Ça a l'air trop bon

    Posté par  . En réponse au journal Galette pomme/noisette. Évalué à 2.

    Le "bon" et le "mauvais" cholestérol désignent bien deux sortes d'acides gras différentes. Note corps a besoin des deux.
    Le mauvais est en bonne partie produit par le corps. Il a tendance à s'accumuler sur la parois interne des vaisseaux sanguins et peut entraîner divers problème à commencer par une rigidification des artères, voir des lésions qui peuvent aller jusqu'à l'accident vasculaire ou cérébrale. Donc bref, il faut en limiter la consommation, surtout pour les personnes à risque: sédentaires et/ou en surpoids.
    Le bon est quand à lui, comme l'a mentionné openbar, essentiel. Cela veut dire qu'il ne peut être produit par le corps. Il a en outre une action bénéfique et réduit le taux de mauvais cholestérols.
    À part ça, entièrement d'accord avec ta conclusion!

  • [^] # Re: Ça a l'air trop bon

    Posté par  . En réponse au journal Galette pomme/noisette. Évalué à 4. Dernière modification le 08 janvier 2016 à 11:28.

    Pas tout à fait: le beurre contient essentiellement des acides gras saturés d'origine animale qui sont unanimement déconseillés par le corps médicale. La margarine est faite à base d'huile végétale qui peut ou ne peut pas contenir des acides gras saturés en fonction de son origine. Certaines peuvent même contenir des omégas 3 ayant une action positive. À éviter certainement: l'huile de palme, de coco, et généralement toute huile riche en acides gras saturés.
    Donc bref c'est une hérésie de dire que le beurre est plus sain que la margarine, surtout compte tenu de la prévalence des problèmes vasculaires associés au surpoids et à l'hypercholesterolémie—qui plus est dans une population constituée en majorité par d'informaticiens ;-)

  • [^] # Re: Ça a l'air trop bon

    Posté par  . En réponse au journal Galette pomme/noisette. Évalué à 2.

    Le problème est surtout que se sont des graisses saturées. Celles qui engendrent des problème vasculaires, taux élevé de cholesterol, etc. Les graisse non-saturée sont généralement ok, sans en abuser évidemment. Certains sont même bénéfiques: oméga 3 (poissons gras, huile de lin).

  • [^] # Re: rtfm

    Posté par  . En réponse au message barre de progression avec nohup.out. Évalué à -2.

    Ok je te la refais. Par contre moi pas pouvoir taper à ta place: double-v gé heu té espace tiret tiret espace cul uh iih euh té espace tiret tiret esse hache ooh double-v tiret pé èr ooh gé èr heu esse esse espace tiret tiret pé èr ooh gé èr heu esse esse égale bé ah èr deux-poins effe ooh ère sé heu deux-points enne ooh esse sé èr ooh elle elle.

  • # rtfm

    Posté par  . En réponse au message barre de progression avec nohup.out. Évalué à 5.

               When the output is not a TTY, the progress bar always falls back to
               "dot", even if --progress=bar was passed to Wget during invokation.
               This behaviour can be overridden and the "bar" output forced by
               using the "force" parameter as --progress=bar:force.
    
               By default, the bar style progress bar scroll the name of the file
               from left to right for the file being downloaded if the filename
               exceeds the maximum length allotted for its display.  In certain
               cases, such as with --progress=bar:force, one may not want the
               scrolling filename in the progress bar.  By passing the "noscroll"
               parameter, Wget can be forced to display as much of the filename as
               possible without scrolling through it.
    
    [...]
    --show-progress
    [...]
               By default, wget only displays the progress bar in verbose mode.
               One may however, want wget to display the progress bar on screen in
               conjunction with any other verbosity modes like --no-verbose or
               --quiet.  This is often a desired a property when invoking wget to
    
    

    De plus, si le seveur http ne renvois pas d'information sur la taille de fichier, tu ne pourras pas avoir de barre de progression…

  • # screen ou tmux

    Posté par  . En réponse au message [Java] JTS3ServerMod. Évalué à 3.

    .

  • [^] # Re: liste de liste

    Posté par  . En réponse au message liste de liste. Évalué à 1.

    ps: avec cette représentation, pour implémenter car, vous devez en réalité créer une nouvelle liste d'un élément. Il serait peut-être plus judicieux de déplacer cdr dans l'union, à vous de voir.

    Autre possibilité (économise un pointeur, mais risque de rendre le code plus compliqué).

    struct node
    {
      enum {LISTE, ENTIER} tag;
      union {
       int ival;
       struct {
         struct node *car;
         struct node *cdr;
       };
      };
    }
  • [^] # Re: liste de liste

    Posté par  . En réponse au message liste de liste. Évalué à 1.

    Je crois que la personne répondait à mon message juste plus haut qui lui demandait si elle avait des notions de lisp. Il me semble que lorsqu'on écrit un simili de lisp, ça peut-être utile de savoir ce que ça fait ;-)

  • [^] # Re: liste de liste

    Posté par  . En réponse au message liste de liste. Évalué à 1. Dernière modification le 06 janvier 2016 à 16:49.

    Ok. Comme je vous l'ai dit, le problème se situe au niveau du type de vos données et des signatures de vos fonctions qui doivent toutes retourner le même type "liste" (que j'ai appellé value dans ma solution). En effet, la beauté de LISP, c'est que tout est une liste ! Ainsi, car,cdr,… prennent une liste et retournent une liste… Ça je pense que vous avez compris.

    Donc l'astuce c'est que votre node doit pouvoir contenir soit un entier, soit une autre liste. Et par conséquent, doit posséder un moyen de "typer" la node pour savoir si elle représente une liste ou une valeur immédiate/un entier, ici grâce au champs "tag".

    struct node3;
    
    struct value {
      enum {LISTE, ENTIER} tag;
      union { struct node3 * lst; int ival; } val;
    };

    J'ai utilisé une "union" mais rien ne vous empêche d'utiliser une "struct", sauf que vous gaspillez ce faisant un peu de mémoire car une valeur ne peut pas être à la fois un entier et une liste.

    Votre type node devient:

    struct node3 {
      struct value car;
      struct node3 * cdr ;
    };
    typedef struct node3 *value;

    Remarquez bien au passage que ma définition de struct node3 contient (embed en anglais) la structure value, et non un pointeur. Cela permet de ne faire qu'une seule allocation pour créer une liste d'un élément (cf. plus bàs).

    Le typedef rend les choses un peu confuses: "struct value" et "value" représente des choses différentes. Il pourrait avantagement être renommé en "liste" pour rendre les choses plus claires. Il rend déja les déclarations de fonctions plus lisibles. Néanmoins, dans les appels à sizeof je garde j'utilise toujours le type de base, question de goût.

    Bref avec cette représentation la construction de cons devient triviale.

    value cons(value head, value tail) {
      if (nil == head)
        return nil;                 /* FIXME: ERROR */
    
      value nouveau = calloc(sizeof(struct node3),1);
      if (! nouveau)
        return nil;                  /* IDEM */
    
      nouveau->car.tag = LISTE;
      nouveau->car.val.lst = head;
      nouveau->cdr = tail;
    
      return nouveau;
    }

    Il vous manque plus qu'un constructeur pour créer un entier. Remarquez qu'un entier est une liste d'un élément de type entier… Remarquez aussi l'utilisation de calloc qui initialise la mémoire à zéro en même temps que de l'allouer.

    value entier(int i)
    {
      value nouveau = calloc(sizeof(struct node3),1);
      if (! nouveau)
        return nil;
    
      nouveau->car.tag = ENTIER;
      nouveau->car.val.ival = i;
      nouveau->cdr = nil;
    
      return nouveau;
    }
    

    Chez moi ça compile, je n'ai pas implémenté le reste de votre exercice mais cela devrait être trivial maintenant.

    int main()
    {
      value l1,l2,l3;
    
      l1 = cons(entier(42),nil);    /* (list 42) */
      l2 = cons(l1,nil);            /* (list (list 42)) */
      l3 = cons(entier(22),entier(23)); /* (list 22 23) */
    
      return 0;
    }
  • [^] # Re: liste de liste

    Posté par  . En réponse au message liste de liste. Évalué à 1. Dernière modification le 06 janvier 2016 à 14:28.

    Est-ce que cela a pu vous mettre sur la voie ? Sinon, qu'est-ce qui ne va pas ? Avez-vous compris maintenant pourquoi votre #define caadr ne pouvait pas fonctionner ?

    Avez vous déja des notions de lisp ? Cela pourrait vous aider à comprendre la finalité de vos exercices qui consistent à première vue à créer un mini interpréteur lisp. Ce lien pourrait, peut-être, vous éclairer: http://stackoverflow.com/questions/23966768/cadr-of-a-list-involving-assoc-function/23967225#23967225

  • [^] # Re: liste de liste

    Posté par  . En réponse au message liste de liste. Évalué à 2.

    J'imagine qu'il s'agit que vous avez maintenant à devoir traiter des listes de listes.
    Dans votre exemple, le membre "car" est un entier, mais vous avez maintenant besoin qu'il puisse être un entier ou (un pointeur vers) une liste. Donc si j'ai bien compris/inféré votre énoncé:

    • Je vous conseillerais, dans un premier temps, de remplacer votre entier par une nouvelle structure --appellons là par exemple "value_t"—qui contiendrait une union des types "int" et "node" et un tag pour discriminer l'union.

    • Ensuite j'écrirais des fonctions "inline" ayant les signatures: value_t* car(node*) et node*cdr(node*).

    • Enfin je me rendrais compte que pour utiliser vos définitions de caar/cadr j'ai besoin d'unifier mes types node et value_t pour ne plus n'avoir qu'un seul type de donnée. Je changerais la définitions de mes fonctions d'accès comme suit: value_t* car(value_t*); value_t* cdr(value_t*). Et je modifierais leur implémentation pour gérer les différents cas de l'union, idem pour putlist. Elles seront maintenant imbricables…

    PS: c'est un peu dommage que vous n'ayez pas fait cette réflexion vous même… Votre "je bloque c'est tout", je l''interprète par "j'ai envie qu'on me donne la solution tout cuit", il aurait été plus intéressant pour vous de nous montrer spécifiquement sur quoi vous bloquer (i.e. une erreure de compilation, un code complet et pas juste des extraits dont on ne comprend pas s'ils viennent de votre énoncé ou d'un de vos camarade…). Sur ce je vous souhaite bon courage et n'hésitez pas à poser une question au cas où vous trouveriez mes explications peu claires!

  • [^] # Re: Bonjour

    Posté par  . En réponse au message Traduction d'un programme C++ en C. Évalué à 2. Dernière modification le 30 décembre 2015 à 11:57.

    Tu dois utiliser la même taille des deux côté. Quelque chose comme:

    const int N_ELEMENTS = 20;
    ...
    malloc(N_ELEMENTS*sizeof(*pointeur));
    fgets(pointeur,N_ELEMENTS*sizeof(*pointeur));
    
    /* Ou encore */
    const int BUFFER_SIZE=20 * sizeof(char); // ou encore 20*sizeof(*pointeur);
    pointeur = malloc(BUFFER_SIZE);
    fgets(pointeur,BUFFERSIZE);

    Ou une n'importe quelle autre combinaison tant que fgets reçoit la même valeur que malloc a reçu. Je préfère la première forme car à chaque utilisation on sait exactement de quoi il s'agit, dans la deuxième forme il reste l'ambiguité : est-ce que buffer_size est exprimé en taille d'octes (= char) ou en nombre d'objet avec le risque de te tromper comme tu l'as justement fait.

    N'oublies pas aussi, comme on te l'a fait remarquer, de vérifier le retour de malloc, i.e. if (0 == pointeur) { return …/exit(1)} par example, et de fgets ! Extrait de la page "man fgets" : fgets() returns s on success, and NULL on error or when end of file occurs while no characters have been read (note: les pages man sont disponibles en traduction française aussi).

  • [^] # Re: Bonjour

    Posté par  . En réponse au message Traduction d'un programme C++ en C. Évalué à 1.

    Et tu auras bien sûr corrigé que c'est sizeof(*ptr_type) qui donne la taille de l'objet pointé à la place de sizeof(type*) qui lui donne justement la taille d'un pointeur (qui aura toujours la même taille, quelle que soit le type de l'objet pointé, soit la taille d'une adresse mémoire).

  • [^] # Re: Bonjour

    Posté par  . En réponse au message Traduction d'un programme C++ en C. Évalué à 1. Dernière modification le 30 décembre 2015 à 11:28.

    Oui, et c'est justement une bonne idée. Je pointe juste une erreur dans la mise en oeuvre qui fait que actuellement tu autorises un dépassement de 3 à 7 fois (sur x86 32 ou 64 bits) la taille du buffer au lieu de t'en prémunir…

    $ cat t.c ; gcc t.c; ./a.out
    #include <stdio.h>
    int main(void){
    char *pointeur;
    printf("sizeof(pointeur)=%d\n",sizeof(pointeur));
    printf("sizeof(*pointeur)=%d\n",sizeof(*pointeur));
    printf("sizeof(char)=%d\n",sizeof(char));
    return 0;
    }
    
    sizeof(pointeur)=8
    sizeof(*pointeur)=1
    sizeof(char)=1

    Là dans ton appel à fgets c'est comme si tu dis "je t'autorise à écrire dans un tampon qui a de la place pour 20 pointeurs", alors qu'en réalité ton tableau n'a de la place que pour 20 charactères.

  • [^] # Re: exercice d'entrainement

    Posté par  . En réponse au message Commande if à écrire. Évalué à 1.

    comparer variableA avec 'true' et :

    À ce que j'ai compris, il doit exécuter le contenu de la variable A.
    Genre, sous la forme d'une fonction:

    mon-if () {
    if $1 ; then $2; fi
    }

    Les mots séparés par des espaces contenus dans $1 seront correctement séparés, c.-à-d. interprêté comme commande, premier argument, deuxième arguments, etc. que si et seulement si la variable IFS contient un charatère espace (ce qui est le cas par défaut…). Tester ensuite avec IFS="".

  • [^] # Re: exercice d'entrainement

    Posté par  . En réponse au message Commande if à écrire. Évalué à 1. Dernière modification le 29 décembre 2015 à 16:03.

    if $var1 -eq 0; then $var2; fi

    Ca ça a l'air bon.

    Nope, ça ne veut rien dire. "if" ne fait que lancer une commande et comparer son code retour à zero, rien de plus. le "-eq" et le "0" seront passés comme arguments à la commande qui est contenue dans $var, à supposer var contient le nom d'une commande valide ou d'une fonction du shell.

    NB "-eq 0" ressemble à la syntaxe du programme test… "test" et "expr" quant à eux ne lancent rien, ils se contentent d'interprèter l'expression qui leur est transmise et de retourner 0 ou pas zero ou d'afficher le résultat pour le cas de expr. Spécifiquement, ils ne font pas d'expansion (ou interpolation ou substitution appellons ça comme on veut) de variable. La seule fonction du shell qui fait ça c'est "eval".

  • [^] # Re: noyau

    Posté par  . En réponse au journal A64 tous gagnants. Évalué à 4. Dernière modification le 28 décembre 2015 à 01:42.

    Bonjour Maxime,

    Tout d'abord merci pour ton super travail sur sunxi-linux. Au titre d'heureux utilisateur d' A10, je voudrais témoigner de ma gratitude à toi ainsi qu'à l'équipe derrière linux-sunxi pour ces remarquables avancées dans le support linux/u-boot qui vont de paire avec une utilisation de linux plus facile et plus fonctionnelle/polyvalente, tout le long de ces dernières années. Je suis toujours agréablement surpris lors de mes visites régulières de la page Mailining_Effort et c'est un plaisir aujourd'hui d'utiliser les versions "mainline" de debian/u-boot/linux sans ne plus devoir patcher quoi que ce soit. La seule "customisation" qui me reste, c'est un dtb pour ajouter une rtc ds1307 bricolée (d'ailleurs j'imagine qu'à un moment je pourrais passer aux overlays pour n'avoir encore moins à faire) . Bref merci beaucoup !

    Je suis assez intrigué par ta remarque, que cela peut-il bien signifier ?
    J'imaginerais déja :
    1) une publication du mystérieux code lima
    2) le retour de simple-drm, augmenté d'une émulation de changement de plan, pour les applications userspace qui sont conçues pour un double buffering (je pense aux EFL que je n'ai pas réussi à faire fonctionner)
    3) un nouveau pilote libre
    4) la libération du pilote propriétaire
    5) une sortie pilote propriétaire en version actualisé
    6) autre chose, mais quoi ?

  • [^] # Re: Bonjour

    Posté par  . En réponse au message Traduction d'un programme C++ en C. Évalué à 2.

    J'ajouterais aussi que l'utilisation systématique des options de compilations -Wall et autres -pedantic permet de débusquer pas mal de mauvaises utilisations et éviter ainsi de prendre de mauvaises habitudes; d'expérience, clang tend (tendait?) à être plus prolifique sur ce point que gcc.
    Et tant qu'à faire, apprendre à utiliser des outils comme gdb, valgrind/memcheck et les analyseurs statiques, dans l'ordre inverse de difficulté mais aussi d'utilité je trouve ;-).

  • [^] # Re: Bonjour

    Posté par  . En réponse au message Traduction d'un programme C++ en C. Évalué à 1.

    ps: tu peux utiliser sizeof(pointeur*);