alf a écrit 255 commentaires

  • [^] # Re: Euh...

    Posté par  . En réponse au message comportement de select dans un module?. Évalué à 0.

    Je pensais qu'on pouvait acceder, aux fonctions userland en mode noyau?

    En programmation C, le noyau tourne dans une "freestanding implementation"(*), car il tourne directement au-dessus du matériel, et ne peut utiliser toutes les possibilités du langage C (une telle implémentation n'est pas obligée de fournir une grande partie de la bibliothèque standard, ni les types complexes). Un programme "normal", qui tourne au-dessus de l'OS est lui dans une hosted implementation, c'est-à-dire une implémentation complète du C (bibliothèque standard entière, et tout et tout).

    Ca, c'est pour le début. Ensuite, select() est défini par POSIX, qui fournit une extension au C. Pour celle-ci, la distinction freestanding/hosted est délibérément plus floue, ce qui fait que le noyau peut fournir un certain nombre de fonctions de POSIX, mais pas forcément toutes. Voici ce que dit POSIX.1, au paragraphehosted implementation ( http://www.opengroup.org/onlinepubs/009695399/nframe.html ) :
    Note that the line between a hosted implementation and a native implementation is blurred, since most implementations will provide some services directly from the kernel and others through some indirect path. (For example, fopen() might use open(); or mkfifo() might use mknod().) There is no necessary relationship between the type of implementation and its correctness, performance, and/or reliability.


    En bref, tu ne peux pas programmer un module noyau avec la doc POSIX sous les yeux, mais la doc du noyau elle-même...

    (*) Bon, peut-être pas strictement conforme, je n'en sais rien, et après tout on s'en fiche, un noyau c'est plein de trucs non-portables par définition, mais on va dire...
  • [^] # Re: NTFS non-supporté en écriture !

    Posté par  . En réponse au message information sur les modules du noyau ? (debutant noyau). Évalué à 1.

    Je ne sais pas où l'info figure, mais c'est archi-connu : le pilote NTFS du noyau Linux ne supporte pas l'écriture.

    Sur le site du projet:
    http://wiki.linux-ntfs.org/doku.php?id=ntfs-fr#est-ce_que_le(...)
    Pour résumer: le pilote du noyau 2.6 peut écrire sur du NTFS si on lui demande, mais ils ne peut pas faire grand chose:
    Le driver peut écraser des fichiers existants, mais il ne peut pas changer la longueur d’un fichier, ajouter de nouveaux fichiers ou effacer des fichiers existants.


    Voilà voilà. Maintenant, si tu veux l'utiliser en écriture, le reste de la FAQ explique clairement comment faire (à quelques fautes d'orthographe près).
  • [^] # Re: bienvenue !

    Posté par  . En réponse au message Les débuts sous Mandriva. Évalué à 0.

    Pour l'installation des programmes va là :
    http://easyurpmi.zarb.org
    et suit ce qui est indiqué.

    Pour expliquer un peu plus: la page easyurpmi.zarb.org permet de configurer l'outil urpmi, qui est l'installeur Mandriva. Elle te permet de choisir, en plus des CD dont tu peux diposer, des sites internet où récupérer les fichier rpm pour installer les logiciels que tu veux. Il y a 3 catégories:
    - "main": la version officielle de Mandriva (la version "figée" lors de sa sortie)
    - "update" pour les mises à jour que Mandriva distribue
    - "contrib" pour des logiciels packagés pour fonctionner avec MandrivaLinux, mais préparés par des gens externes à la société Mandriva (en particulier le groupe "Penguin Liberation Front", qui fait du très bon boulot et distribue plein de logiciels pour ta Mandriva).
    Un fois le processus fini, il te donne des lignes de commandes à taper (en tant qu'administrateur) pour configuer ton urpmi. Par la suite, quand tu voudras installer des logiciels à travers l'interface de la Mandriva (soit l'interface graphique, soit urpmi), il utilisera ces sources de données.
  • [^] # Re: WinModem

    Posté par  . En réponse au message Les débuts sous Mandriva. Évalué à 0.

    Si tu comprends un peu l'anglais, j'ai bien trouvé http://www.linuxquestions.org/questions/showthread.php?p=217 , mais c'est déjà très technique pour un débutant... (Si quelqu'un a trouvé un meilleur lien, faut pas hésiter à partager ;)
  • # WinModem

    Posté par  . En réponse au message Les débuts sous Mandriva. Évalué à 0.

    Mis à part ce qui a déjà été dit, pour les portables sous linux, j'ai deux sites de référence: http://tuxmobil.org/ et http://www.linux-on-laptops.com/ qui (entre autres) listent les portables pour lesquels des gens ont faits des tests d'installation de Linux. En particulier, chacun a une page par constructeur, dont Compaq, ce qui donne:
    Compaq Presario 2120 EA: http://draco.altervista.org/notebook/notebook.html (en italien)
    Portable Compaq Presario 2120eu Athlon : http://www.smartbooking.biz/fanch/CPQ_Fr.php (en français)

    Personnellement, j'ai un Presario 2800 (qui tourne sous Mandrake 10.1, d'avant qu'ils ne s'appellent Mandriva), donc le matériel peut être différent du tien. Le 2800 fonctionne avec un winmodem Conexant HSF 56k HSFi (d'après le dernier lien, le 2120 EU utilise aussi un winmodem, à vérifier).

    Si tu ne connais pas le terme winmodem (<ma vie>que j'ai appris à haïr, comme ces incapables de chez Compaq pas fichus capables de pondre un bios ACPI correct</ma vie>), il s'agit d'un composant matériel ayant les fonctionnalités d'un modem, mais réduit à son minimum (ou peu s'en faut), si bien qu'il est nécesaire d'avoir un composant logiciel spécifique pour le faire fonctionner, i.e. plus que pour un modem normal. La dénomination "winmodem" est venue du fait que ces modems sont le plus souvent distribués avec le bout de logiciel pour Windows, mais pas pour le reste des systèmes d'exploitations (dont GNU/Linux), et que les spécifications ne sont pas ouvertes (ce qui fait qu'il est très difficile de créer un pilote pour ces matériels).
    En résumé, il s'agit d'un matos au rabais dont on ne sait même pas comment ça marche.

    Pour en revenir au Presario 2800, ça fait longtemps que je n'ai pas regardé ce qui se fait (je ne l'utilise plus beaucoup depuis un moment, donc je m'acharne moins dessus), mais il y avait un pilote libre fourni par Linuxant ( http://www.linuxant.com/drivers/ ) qui marchait bien. Sauf que Linuxant a ensuite changé de politique: ils distribuent mainteant un driver libre bridé (en débit) et un non-libre non bridé. Dixit leur site:
    Due to intellectual-property/patent issues beyond our control, the source code of some components like modem modulations cannot be released; however, we have attempted to reduce the inconvenience of binary-only modules by separating the proprietary code from the operating-system specific code. The latter is provided in source form, allowing users to install the drivers under any supported version of the Linux kernel.
    [...]
    Because the scope of this project has grown beyond the capacity of a single volunteer and legal issues prevent us from using a classic open-source development model, the modem drivers are now available in two editions:
    # a free version (limited to 14.4Kbps data), available at no cost. Please use it to test if your hardware is compatible.
    # a full version (with 56K and FAX), available for a modest price.


    No comment sur leur politique, mais note que les anciennes versions (libres non bridées) sont toujours dispo, quoique pas forcément sur leur site...

    Et si ton modèle n'utilise pas de modem Conexant, bah... Faut chercher plus loin.

    Ah, j'oubliais: http://linmodems.org/ est un projet pour le support des winmodems sous Linux, tu peux regarder là-bas ce qu'ils ont. Il doit y être expliqué comment vérifier de quel matériel tu disposes.

    PS: je ne suis plus très sûr si pilote Linuxant était libre ou juste gratuit+open source, ça fait un moment que je n'ai pas lu leur(s) licence(s). A vérifier.
  • [^] # Re: automake & co.

    Posté par  . En réponse au message fichier Makefile.in et make. Évalué à 3.

    Plus précisément: le développeur / mainteneur de l'application écrit un fichier Makefile.am qui décrit ce dont a besoin l'application; et ensuite il lance le bastringue des autotools, dont automake qui crée le fichier Makefile.in à partir du fichier Makefile.am. En passant les différentes étapes des autotools qui ne sont pas pertinentes ici, il arrive à fournir une archive contenant entre autres le Makefile.in et le script configure.

    C'est alors à l'utilisateur de lancer le script configure sur sa propre machine, qui va faire tous les tests qui vont bien et, si tous les tests passent, créer le fichier Makefile à partir des informations dont il dispose, dont le Makefile.in (il y a aussi d'autres fichiers, mais je résume).

    Et ensuite l'utilisateur peut compiler son application (make), l'installer (make install) ou faire un peu ce qu'il veut suivant ce que le Makefile contient (les Makefile générés par les autotools sont plutôt complets de ce côté, et extensibles). Mais note bien que le fichier n'est normalement pas créé si configure rencontre un problème. Vérifie ce qu'il raconte, et les logs (je crois que le fichier de log s'appelle configure.log, de tête...).

    C'est cette procédure qui se traduit assez souvent par la ligne de commande
    ./configure && make && make install

    dans des documentations un peu expéditives... (et, personnellement, je ne procède pas ainsi: le make install nécessite bien souvent des droits d'admin, sous lequel je n'ai pas forcément envie de tester le code que j'ai téléchargé... J'utilise plutôt un compte non privilégié pour compiler-tester, puis je passe en admin pour installer).

    Pour en revenir au problème, je pense qu'il faut regarder du côté des logs de configure. S'il n'indique rien de particulier, vérifie si le fichier Makefile a bien été généré; sinon il faut corriger ce qui pose problème (les logs de configure peuvent ne pas être très explicites parfois...).
  • # Petits problèmes

    Posté par  . En réponse au message Tableau dynamique de pointeur vers char. Évalué à 1.

    char now[2] = "a";te>
    char *message[1];
    /* ... */
    message[count] = malloc(sizeof(char) * 2);
    strcat (message[count], now);

    Comme il a été dit plus haut, la définition de tes données ne correspond pas au traitement que tu en fais: actuellement tu définis message comme un pointeur sur tableau(x) de un caractère, alors que tu l'utilises comme un pointeur sur tableau(x) de deux caractères (strcat inclut le '\0' final)...

    Par ailleurs, sizeof(char) vaut 1 par définition, tu peux donc simplifier ton code.

    char now[2] = "a";
    /* ... */
    while ((now[0] = fgetc(fp)) != EOF)
    /* ... */
    Ta boucle peut s'arrêter avant la fin du fichier, car fgetc() renvoie autre chose qu'un char: un int qui contient soit un caractère valide sous forme d'unsigned char, soit EOF. Or, tu convertis implicitement cette valeur int en un char, et si la valeur n'est pas représentable directement, alors il y peut y avoir "collision", et un caractère valide sera vu comme EOF (cf. http://c-faq.com/stdio/getcharc.html ).

    message = realloc(message, (count + 1) * sizeof(char *));

    Attention à l'utilisation de realloc(): si la fonction ne peut allouer de mémoire, elle renvoie NULL sans forcément libérer l'ancienne zone mémoire. Dans ton cas, ça reviendrait à mettre message à NULL sans faire le free(), d'où une fuite mémoire.

    De plus, au lieu de faire un realloc() à chaque étape, ce qui peut faire perdre du temps (il peut y avoir des appels système derrière et différents traitements plus ou moins lourds), il peut être préférable de le faire en doublant la taille du vecteur à chaque appel (en gardant un paramètre size qui contient la taille réelle du vecteur, et si count > size, alors on fait un realloc avec 2*size).
  • [^] # Re: c'est plus amont

    Posté par  . En réponse au message Tableau dynamique de pointeur vers char. Évalué à 0.

    Il ne faut pas caster le résultat de *alloc() (on n'est pas en C++).
    http://c-faq.com/malloc/mallocnocast.html

    Et le surlignage peut se faire avec les balises <tt> et </tt>.
  • [^] # Re: Quel compilateur sur quelle plateforme ?

    Posté par  . En réponse au message Probleme de précision. Évalué à 0.

    Comme le dit ton second lien, il y a un probleme fondamental a faire de l'arithmetique decimale pour des chiffres [1;0]: la representation binaire ne correspond pas a un chiffre parfaitement precis (ie: nombre limites de chiffres significatifs).

    Plus généralement (et plus exactement), il y a un probleme fondamental à faire de l'arithmetique décimale sur les ordinateurs utilisant une représentation binaire.
    Comme expliqué sommairement dans le premier lien de mmMMOoooOMMmm, sur un ordinateur utilisant en interne des puissances de 2 pour représenter les nombres flottants, aucune puissance négative de 10 ne peut être exactement représentée (i.e. 0,1 ou 0,000001 par exemple). Les calculs flottants sur ordinateur ont une part d'imprécision qu'il faut savoir maîtriser (ce que je ne prétends pas). Le langage C suit la norme IEEE754 sur l'arithmétique flottante (cf. annexe F de la norme C); cette dernière est indépendante de tout langage ou matériel (c'est justement son intérêt) et, pour information, le C n'est pas le seul langage à l'utiliser (Java aussi, et à mon avis bien d'autres...).

    Pour des informations beaucoup plus précises et complètes que ce que j'ai pu écrire au-dessus, mais néanmoins plus compréhensibles, sur ces calculs flottants et en particulier sur la norme IEEE754, lire l'article "What every computer scientist should know about floating-point arithmetic" de David Glodberg, publié dans l'ACM, et disponible en ligne à http://portal.acm.org/citation.cfm?doid=103162.103163 . Il s'agit d'un article très clair, et souvent référencé. C'est devenu ma référence dans le domaine ;) Plutôt que de te le résumer dans ce post, au risque de dire des dizaines d'âneries, je préfère te donner le lien (je viens même de voir que c'est le premier article référencé sur la page du groupe de travail de la norme IEEE754 http://grouper.ieee.org/groups/754/ !).

    Je viens de tomber (suite aux liens précédents) sur http://grouper.ieee.org/groups/754/faq.html#binary-decimal qui répond à ta question ;), et renvoie à une FAQ qui traite entièrement du calcul décimal (mais sur une autre norme, semble-t-il)

    Pour revenir au C, voir aussi la FAQ du newsgroup comp.lang.c, qui contient un chapitre dédié au calcul flottant: http://c-faq.com/fp/index.html .

    Si ça n'étanche pas ta soif de savoir, tu peux lire l'annexe F de la norme C, et la documentation de ton comilateur (cf. l'annexe J.3.6 de la norme qui liste les points sur lesquels une implémentation C doit documenter ses choix).
  • [^] # Re: valgrind ou electric fence

    Posté par  . En réponse au message incompréhensible - utilisation d'ALSA. Évalué à 1.

    J'ai pensé de même à un débordement de tampon. En lisant l'API ( http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.(...) ): dans l'exemple http://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2latenc(...) , snd_pcm-readi() est appelée avec un char* pour deuxième paramêtre. Or un short n'a pas la même taille qu'un char (pourtant on a sizeof(short) >= sizeof(char) (et sizeof(char) == 1), donc remplacer short par char dans ce code ne résoudra pas ce problème. Mais c'est un indice...)
    Mais il faudrait quelqu'un qui connaît mieux l'API pour savoir d'où vient le problème... Dans l'API de snd_pcm-readi(), ils parlent aussi bien de frames que de bytes.

    Si le paramètre size correspond à un nombre de bytes, alors il est préférable de définir le buffer comme un char[LEN] (ou char* avec malloc) et de passer sizeof buf (ou la longueur passée à malloc) comme troisième paramètre.

    Si le paramètre size est un nombre de frames, alors je ne sais pas, il faut voir comment ALSA définit une frame (peut-être la taille d'une frame dépend-elle de la qualité du son, i.e. bitrate ?). Pour info, un short contient au moins 16 bits (une implémentation peut avoir un short plus grand, mais ce n'est pas garanti).

    En tout cas, je suis d'accord avec ton diagnostic, c'est un simple débordement de tampon. Reste à savoir d'où il vient.

    (en passant, j'ai des gros doutes sur les lignes d'include:
    #include "string.h";

    On inclut un en-tête de la bibliothèque standard avec les crochets < > au lieu des guillemets, et on ne place pas de ; à la fin de la ligne:
    #include <string.h>

    Ca me semble étonnant qu'une telle syntaxe soit acceptée par un compilateur C, ça doit être une extension...)
  • [^] # Re: PCRE

    Posté par  . En réponse au message regex.h Lazy Mode. Évalué à 1.

    Bon du coup je poste pas de code je risque de pas etre fully compatible ANSI C ISO 99... Des fois que ca jetterai le trouble chez quelques personnes... ANSI rigides...

    :)
    Je n'ai rien contre les extensions au C (POSIX, GNU... ou tout ce qui tourne sur ta machine), par contre j'en ai contre les erreurs de programmation (en C, un comportement indéfini est une erreur). Quand un programme peut tenter d'accéder à une zone mémoire qui ne lui appartient pas, je ne vois pas en quoi c'est être rigide de dire qu'il y a un problème potentiel.
    Peut-être savais-tu que c'était une erreur dans ton code d'exemple, dans ce cas tu pouvais l'écrire, même en commentaire dans le code.
    De même pour les include, ça ne t'aurait pas coûté pas grand chose d'ajouter deux lignes à ton programme.
    Pour d'autres points (main, ou return 0, par ex.), je voulais juste montrer une autre façon de faire (le main() sans argument est quand même deprecated depuis un moment...). Juste une question de style, sans plus.

    Voilà. Maintenant, je suis content pour toi si tu as trouvé une solution à ton problème, qu'elle soit C ISO ou non d'aileurs, ou même dans un autre langage. L'important est que ta machine fasse çe que tu veux qu'elle fasse...

    (et, cf. mon autre post, le problème ne viendrait peut-être pas directement de la glibc, mais des spécifications POSIX, que la glibc semble respecter pour le coup)
  • [^] # Re: Une idee comme ça...

    Posté par  . En réponse au message regex.h Lazy Mode. Évalué à 1.

    Je ne demande pas le code complet de son projet, juste un code compilable.
    Et je ne prétends pas le sauver de la perdition, je note juste un certain nombre de problèmes (plus ou moins importants) dans son code.

    Et non, je n'ai pas la réponse à sa question, je ne sais pas quel est l'endroit exact où son code s'écarte du comportement qu'il attend (à part peut-être ci-dessous). Mais j'ai repéré des endroits où le comportement est indéfini, i.e. tout et n'importe quoi peut se produire, y compris et surtout quelque chose qu'il ne veut pas (typiquement, un comportement indéfini peut causer une erreur de compilation, ou une erreur de segmentation à l'exécution si ça compile, ou un programme qui ne plante pas mais a un comportement incorrect), et je lui ai fait remarquer qu'en vérifiant les codes de retour des fonctions qu'il appelle, il pourrait cerner le problème plus facilement...

    Après, je n'ai pas de compilateur C sous la main pour l'instant, je ne peux donc tester son code. Je n'ai pas utilisé regex.h, donc je ne peux voir s'il s'agit d'une erreur (évidente ou non) d'utilisation de ces fonctions.

    A part peut-être, dans la doc POSIX (que j'ai donnée dans mon premier mail), je viens de trouver ça:
    When matching a basic or extended regular expression, any given parenthesized subexpression of pattern might participate in the match of several different substrings of string, or it might not match any substring even though the pattern as a whole did match. The following rules shall be used to determine which substrings to report in pmatch when matching regular expressions:

    1. If subexpression i in a regular expression is not contained within another subexpression, and it participated in the match several times, then the byte offsets in pmatch[ i] shall delimit the last such match.

    Donc le résultat qu'il obtient vient peut-être de là...
  • [^] # Re: Une idee comme ça...

    Posté par  . En réponse au message regex.h Lazy Mode. Évalué à 0.

    Tu poses une question, j'essaye d'y répondre, avec mes connaissances. J'ai soulevé deux comportements indéfinis dans ton programme, ce qui signifie qu'étudier tout comportement de ce programme tel quel est inutile. Il est indéfini au niveau du C ISO (cf. malloc) et au niveau de POSIX.2 (cf. regcomp), donc tout peut arriver.

    J'ai aussi remarqué (et c'est lié à ce qui précède) que tu ne testais pas les codes de retour des fonctions que tu appelles, ce qui t'empêche de savoir à partir d'où il s'écarte du comportement que tu attends. Si tu le faisais, tu pourrais cerner plus précisément le problème, et le résoudre assez vite (à mon avis). Etait-ce inutile de te le dire ? Avec le code que tu as posté, tu ne sais pas si regcomp plante, si c'est regexec, malloc, memcpy ou printf...

    Pour le type de main(), désolé si ça t'énerve, mais il y a des gens dans d'autres fora ou newsgroups (pas moi, note) qui ne prennent même pas la peine de répondre à ceux qui ne savent pas comment l'écrire. J'ai pris la peine de te dire que ton code comportait un souci à ce niveau (plus précisément, et sauf erreur de ma part, utilisation d'une deprecated feature du C ISO, datant de l'époque K&R), et je t'ai donné les deux prototypes portables. J'aurais pu ne pas le faire. Libre à toi de ne pas prendre en compte mon message sur ce point.

    Tiens, en passant, je n'avais pas fait attention que printf() et memcpy() n'avaient pas leur include non plus (respectivement stdio.h et stdlib.h). Pense à utiliser un niveau de warning suffisant pour ton compilateur (-O2 -Wall -Wextra pour gcc 4, par exemple (de tête)).
  • # Une idee comme ça...

    Posté par  . En réponse au message regex.h Lazy Mode. Évalué à -1.

    int main(){

    Non: int main (void) ou int main(int argc, char *argv[]) (ou une formulation équivalente pour la seconde). Tout autre prototype est une extension; et le int main() seul est un prototype incomplet.
    regcomp (&preg, "(.*?)toto" , REG_EXTENDED|REG_ICASE);

    regcomp() renvoie un code de sortie, il faut le vérifier. POSIX.2 [1] dit:
    Upon successful completion, the regcomp() function shall return 0. Otherwise, it shall return an integer value indicating an error as described in <regex.h>, and the content of preg is undefined. If a code is returned, the interpretation shall be as given in <regex.h>.

    Note bien le undefined. En jargon C, ça veut vraiment dire indéfini, i.e. si tu accèdes au contenu de preg après une erreur de regcomp, tout peut se produire, du comportement que tu pensais obtenir, jusqu'au plantage, au crash disque, ou à des démons qui sortent de ton nez.

    Idem pour regexec():
    Upon successful completion, the regexec() function shall return 0. Otherwise, it shall return REG_NOMATCH to indicate no match.
    (enfin, tu n'es pas obligé pour regexec(), ça dépend du traitement que tu fais après. Pour un debug, je te conseille de vérifier le résultat).

    char * match = malloc(len+1);

    Il faut vérifier le résultat de *alloc(). En cas d'échec de cete fonction, si tu ne fais pas cette vérification, tu déréférenceras un pointeur nul, d'où un comportement indéfini, soit la ligne suivante (memcpy() avec un len non nul), soit celle d'après (si len est nul).
    De plus, il manque le #include <stdlib.h>, d'où encore un comportement indéfini: sans prototype de malloc visible, le compilateur est obligé de supposer que la fonction renvoie un int. Comme tu assignes cette valeur à un pointeur, cela viole une contrainte (6.5.16.1 du n1124), d'où un comportement indéfini. Si tu rajoutes un cast, le comportement n'est plus indéfini (les contraintes sont vérifiées), mais dépendant de l'implémentation (conversion d'entier en pointeur, 6.3.2.3p5, et 6 pour la conversion inverse). La bonne solution est donc de placer le #include qui va bien.

    printf("%s\n",match);
    }
    Un return 0; (ou return EXIT_SUCCES; avec l'include qui va bien) serait mieux, vu que main() renvoie un int. C99 autorise de ne pas le faire, mais c'est toujours mieux de finir une fonction ne renvoyant pas void par un return XX;.

    [1] http://www.opengroup.org/onlinepubs/009695399/toc.htm Il faut s'inscrire, mais c'est gratuit et téléchargeable par la suite, ou consultable en ligne.
  • # Une idée comme ça...

    Posté par  . En réponse au message contrôle d'un process Java par un process C. Évalué à 2.

    Quand tu dis que ton processus Java plante, c'est qu'il plante lamentablement avec une exception, ou que tu as fait un System.exit() ?

    Le mieux, c'est de gérer dans ton programme Java la sortie de manière propre: suivant ce qui se passe, tu sors avec un System.exit(code), ou code prend une valeur non nulle en cas d'erreur, ou 0 si tout va bien. Au passage, la doc de l'API Java indique juste que "By convention, a nonzero status code indicates abnormal termination", la traduction entre le code que tu donnes à exit() et ce que le système reçoit n'est pas spécifiée (à ce que j'ai trouvé dans l'API et la Java language specification, mais je peux me tromper).

    Par là-dessus, tu peux faire, soit un script shell si c'est autorisé (portabilité, contraintes, tout ça), comme Benoit Plessis te l'a indiqué plus haut, soit un programme C tout simple qui fait la même chose avec system() (ou fork() puis un exec* si tu y tiens) pour lancer le processus. Pour recevoir la fin du processus, tu peux utilider un gestionnaire de signaux avec signal(), ou faire directement un wait(). Le gestionnaire de signaux a l'avantage de permettre à ton processus C de faire autre chose pendant ce temps, le wait() bloquant le processus jusqu'à l'arrivée d'un signal. Cependant, avec un gestionnaire de signaux, le "traitement principal" fait par ton processus C peut être interrompu à tout moment. donc la conception et le codage doivent être adaptés (réentrance, principalement, ou le cas des processus multi-threadés).
    system() et signal() sont du C ISO, mais wait(), fork(), les exec*() et SIGCHLD, qui codifie le signal "mort d'un processus fils" pour signal() sont POSIX (le C ISO ne définissant pas les notions de processus père/fils, ou même de parallélisme, de threads ou quoi que ce soit dans le genre).
  • [^] # Re: Buffer overflow power

    Posté par  . En réponse au message les sémaphores nommés. Évalué à 4.

    char n[20], p[20];

    printf("Nom:"); fgets(n, sizeof(n) * sizeof(char), stdin);
    printf("Prenom:"); fgets(p, sizeof(p) * sizeof(char), stdin);

    c'est plus secure quand même.

    Presque.

    Comme n est du type char[20], on a: sizeof(n) == 20 * sizeof (char). Donc ta formule est incorrecte. Note qu'elle renvoie le bon résultat numérique, mais seulement par coïncidence: la façon dont elle est exprimée laisse croire que, pour un tableau, sizeof tab renvoie le nombre d'éléments, alors qu'elle renvoie le nombre d'éléments fois la taille de l'élément (le nombre d'éléments est obtenu par sizeof array / sizeof array[0]).
    Tu obtiens le bon résultat dans ton cas, seulement parce que sizeof (char) == sizeof (unsigned char) == sizeof (signed char) == 1. C'est garanti par la norme C (6.5.3.4p1 du n1224).
    Dans tout autre cas, sizeof MonType >= 1. Pour fgets(), ça n'a aucun impact, vu qu'il attend des char mais, pour toute autre fonction, ta formule indiquerait à la fonction que le tableau fourni en paramètre a une taille plus grande qu'en réalité, d'où des risques de buffer overflow, ou de perte mémoire (je pense aussi à malloc(), si tu demandes plus de mémoire que ce dont tu as besoin, ce sont des pertes sèches...).

    Pour en revenir à ce bout de code précis, si on suppose que tu as mis simplement sizeof n, alors ton programe est plus sûr... jusqu'à ce que l'utilisateur rentre un nom de (au moins) 19 caractères... Dans ce cas, le premier fgets() mange les 19 premiers caractères, y ajoute un '\0', et rend la main en laissant le '\n' dans stdin. Le deuxième fgets() mangera tout de suite le '\n', et retournera après y avoir ajouté le '\0'.
    Tu obtiendras donc un nom de 19 caractères, et un prénom qui vaut '\n'. Idem pour le prénom, sachant que les caractères en trop dans stdin seront lus plus tard dans le code, et pas forcément là où on s'y attendrait...

    Avec fgets(), il faut tester la présence de '\n' dans le buffer, et lire la suite s'il n'y est pas (sauf si on a rencontré la fin du flux, évidemment). La bonne réponse est donc fgets(n, sizeof n, stdin); suivi d'une boucle de vérification de la présence de '\n' (avec strchr()) ou de fin du flux, et d'une relecture si nécessaire; le tout encapsulé dans une fonction générique, pour que tu n'aies pas à la recoder 20 fois (note aussi que ça se trouve sur le vaste internet, cd. http://cbfalconer.home.att.net/download/ggets.zip par exemple, faite par un connaisseur du C et "régulier" sur comp.lang.c).

    P.S.: fflush(stdin) a un comportement indéfini, ça n'est autorisé que sur stdout.

    Pas seulement. 7.19.5.2p2:
    If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined.
    Donc stderr ou tout autre flux sortant est valide pour fflush().
  • [^] # Re: #include <sem.h>

    Posté par  . En réponse au message les sémaphores nommés. Évalué à 2.

    Essayes également de rajouter des arguments comme gcc -Wall -pedantic pour avoir plus d'information sur les erreurs.
    Je fais plutôt gcc -W -Wall [-std=XXX [-pedantic]]. Le -W est à remplacer par -Wextra en GCC 4; -std=XXX pour spécifier la version de C, et -pedantic sert à ajouter des warnings demandés par la norme C et à d'autres choses (c'est moi qui souligne):
    -pedantic
    Issue all the warnings demanded by strict ISO C and ISO C++; reject all programs that use forbidden extensions, and some other programs that do not follow ISO C and ISO C++. For ISO C, follows the version of the ISO C standard specified by any -std option used.

    Valid ISO C and ISO C++ programs should compile properly with or without this option (though a rare few will require -ansi or a -std option specifying the required version of ISO C). However, without this option, certain GNU extensions and traditional C and C++ features are supported as well. With this option, they are rejected.

    -pedantic does not cause warning messages for use of the alternate keywords whose names begin and end with `__'. Pedantic warnings are also disabled in the expression that follows __extension__. However, only system header files should use these escape routes; application programs should avoid them. See Alternate Keywords.

    Some users try to use -pedantic to check programs for strict ISO C conformance. They soon find that it does not do quite what they want: it finds some non-ISO practices, but not all—only those for which ISO C requires a diagnostic, and some others for which diagnostics have been added.
    [ source:http://gcc.gnu.org/onlinedocs/gcc-4.0.2/gcc/Warning-Options.(...) ]
    Donc -pedantic rejettera les programmes utilisant des extensions au C "pur ISO", dont POSIX, par exemple, ou peut-être les IPC... (j'ai pas vérifié pour les IPC, mais je me suis déjà fait jeter par -pedantic pour du POSIX)

    Et, au passage, je n'utilise -pedantic qu'avec -std=XXX, pour bien savoir quelle version/extension de C j'utilise (et aussi au cas où quelqu'un pase derrière et ne connaît pas la version C par défaut de gcc, ou s'il utilise un autre compilateur, ou quand gcc changera de version C par défaut...).
  • [^] # Re: En passant...

    Posté par  . En réponse au message shm_open() référence indifinie !!!. Évalué à 2.

    C'est vrai, j'avais lu en très grande diagonale, sachant que la réponse au pbolème était déjà donnée.. Mais c'est vrai que
    pg_addr = (caddr_t) mmap(0, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED,fd, 0);
    if (pg_addr == (caddr_t) -1)
    {
    perror("mmap failure");
    exit(0);
    }
    est très moche. Caster -1 en pointeur, c'est assez ignoble (au passage, c'est non portable). mmap() renvoie MAP_FAILED en cas d'erreur (suivant POSIX; après si l'implémentation n'est pas conforme, c'est autre chose...).
    De plus, exit(0) pour signaler une erreur ! EXIT_FAILURE sert à ça.
    Qui plus est, faire un exit() alors qu'on a soi-même défini une fonction Quitter, c'est illogique.

    En relisant un peu mieux, on a aussi:
    - fflush(stdin);, cf. http://c-faq.com/stdio/stdinflush2.html .
    - scanf(), cf. http://mapage.noos.fr/emdel/notes.htm#saisie
    - int size = sizeof(FICHE);, alors que sizeof renvoie un size_t, et que c'est justement ce que mmap() est censé recevoir...
  • [^] # Re: En passant...

    Posté par  . En réponse au message shm_open() référence indifinie !!!. Évalué à 3.

    Oups... J'ai mangé un mot en citant le paragraphe 7.19.1p3
    EOF
    which expands to an integer constant expression, with type int and a negative value
    . (c'est moi qui souligne).

    Et mon commentaire
    Donc, envoyer le résultat de getchar [...] dans un char peut causer une perte d'information si ton implémentation définit le char comme signé.
    est incomplet: la perte d'information arrivera même si le char est non signé (vu que EOF est une valeur qui se rajoute à l'ensemble des valeurs valides des caractères).
  • # En passant...

    Posté par  . En réponse au message shm_open() référence indifinie !!!. Évalué à 3.

    Pour avoir un prototype complet, il faut préciser les paramètres. Dans le cas où une fonction ne prend pas de paramètre, il faut la déclarer ainsi:
    type_retour nom_fonction(void)

    Si on la définit de la manière que tu as faite
    type_retour nom_fonction()
    alors on retombe sur les "anciennes" déclarations (au sens C), et aucun contrôle n'est fait par le compilateur sur les paramètres envoyés: voir la phrase 6.7.5.3.p14 du n1124:
    The empty list in a function declarator that is not part of a
    definition of that function specifies that no information about the number or types of the parameters is supplied.

    comparée avec 6.7.5.3.p10:
    The special case of an unnamed parameter of type void as the only item in the listspecifies that the function has no parameters.

    Donc avec tes protoypes
    void Menu();
    void Ecrire();
    void shmsem();
    void Lire();
    void Quitter();
    tu as le droit d'appeler ensuite les fonctions avec des paramètres quelquonques, ce qui diminue l'utilité du protoype...
    - - - - - - -
    main()
    {

    Les deux seules manières portables de définir main sont int main(void)et int main(int argc, char **argv) (ou des définitions compatibles, comme char *argv[]). Le reste est dépendant de la plate-forme.

    - - - - - - -
      char car;
      do
      {
        <snip>
        /* ignore tous les caracteres non alphanumeriques */
        while(!isalnum(car=getchar()));

    Non. getchar() renvoie un int. Sa valeur de retour exacte est:
    - soit le prochain caractère en unsigned char;
    - soit EOF si le flux est "fini".
    cf. 7.19.7.1p2
    If the end-of-file indicator for the input stream pointed to by stream is not set and a next character is present, the fgetc function obtains that character as an unsigned char converted to an int

    7.19.7.1 p3:
    If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the endof-
    file indicator for the stream is set and the fgetc function returns EOF.

    et 7.19.1p3
    EOF
    which expands to an integer constant expression, with type int and a negative

    Donc, envoyer le résultat de getchar (qui est un équivalent de getc(stdin), lui-même (quasi) équivalent à fgetc(stdin)) dans un char peut causer une perte d'information si ton implémentation définit le char comme signé.
    En pratique, EOF peut valoir par exemple -1, qui correspond parfois à la valeur signed char du caractère ÿ, si je me souviens bien. Ce qui signifie que, si tu lis ce ÿ avec ton code (ou d'autres caractères suivant l'environnement), sa valeur unsigned déborde la capacité du signed char, et retombe sur -1 par les règles de conversions entières. Tu croiras voir un EOF, donc isalnum() renvoie faux, et le while le bouffera sans broncher... Dans ton cas, ce n'est pas forcément grave, mais l'erreur peut porter à conséquence dans d'autres contextes.
  • [^] # Re: Documentation incorrecte

    Posté par  . En réponse au message Appel systeme send (). Évalué à 1.

    int where_len;
    (...)
    where_len = sizeof (where);
    if (getsockname (sockfd,
    (struct sockaddr *) &where,
    (socklen_t *) &where_len) < 0) {
    Erreur: tu déclares where_len comme int, mais tu y mets un size_t, que tu utilises ensuite comme un socklen_t (qui fait au moins 32 bits suivant POSIX)...
    Je n'ai pas regardé en détail la norme, mais la relation entre int et size_t ne semble pas définie. J'ai juste trouvé dans 7.17p4 une recommandation que size_t ne soit pas plus grand que long.

    buf = (char *) malloc (buf_len);

    En C, contrairement au C++, on ne DOIT pas caster le retour de malloc(). 1) c'est inutile et 2) ça peut cacher l'absence de l'include correspondant. Et si on utilise une fonction sans avoir son prototype, on se rapproche du comportement indéfini (je ne me souviens plus du statut exact, mais je soupçonne l'UB).
    Je suppose que, dans ton "vrai" code non simplifié, tu vérifies le retour de malloc().

    for (i = 0; i < len; i+= buf_len) {
    int sz;
    sz = MIN (buf_len, (len - i));

    if (send (sockfd, buf, sz, 0) != sz) {
    Pourquoi n'as-tu pas déclaré sz de type size_t ? Idem pour i et len; je ne vois pas pourquoi tu utilises des int alors que tu as besoin de size_t, vu que malloc, sizeof, send et plein d'autres travaillent avec ce type. En utiliser un autre mène tôt ou tard à avoir des valeurs hors domaine, et à des bugs difficilement identifiables.
    Ca a peut-être l'air de chipotage, mais puisque C et POSIX se décarcassent à définir des prototypes précis pour leurs fonctions, autant les respecter.

    Je ne sais pas si ça résoudra ton problème précis, mais au moins ça t'en évitera d'autres.
  • [^] # Re: Documentation incorrecte

    Posté par  . En réponse au message Appel systeme send (). Évalué à 1.

    Pour information, le processus à l'autre bout de la socket, il reçoit quoi quand tu rencontres ce comportement ?

    De plus, est-ce que la longueur du buffer correspond bien à l'argument length ? et ca tient bien dans un size_t ?
  • # Documentation incorrecte

    Posté par  . En réponse au message Appel systeme send (). Évalué à 1.

    Dans la norme POSIX "IEEE Std 1003.1, 2004 Edition" [1], il est dit pour send():
    RETURN VALUE

    Upon successful completion, send() shall return the number of bytes sent. Otherwise, -1 shall be returned and errno set to indicate the error.

    Ton implémentation de send() est donc peut-être correcte, mais sûrement pas la doc (conforme ou pas, de toute façon il y a un écart entre le code et la doc, donc un rapport de bug s'impose).

    [1] http://www.opengroup.org/bookstore/catalog/t041.htm
  • [^] # Re: il faut passer le tableau en reference

    Posté par  . En réponse au message Extraction sous-chaînes. Évalué à 1.

    si tu fais &tab c''est une reference a un tableau de 4 pointeurs, donc il faut que la fonction ait un prototype :
    msg_intercept(char * msg, char * del , char *tab[4])

    ce qui est penible

    Plus que la pénibilité, c'est la sécurité du code qui est en jeu: à moins que je ne me trompe lourdement, tu peux bien passer un tableau de n'importe quelle taille à ta fonction, il n'y a pas de contrôle (imposé par la norme, s'entend). D'où des problèmes si tu veux accéder à tab[3] alors que tu lui as passé un tableau de taille 2, ou si tu lui as passé un tableau de taille 6... (mais peut-être je me trompe; j'ai peut-être confondu avec les cas void f(char *str) et void f(char str[4])).

    Donc la fonction peut etre :
    msg_intercept(char * msg, char * del , char **tab, int nb)
    Ou, en C99:
    msg_intercept(char * msg, char * del , int nb, char *tab[nb])
    Mais c'est une fonctionnalité (les tableaux de taille variable, ou VLA) qui est "broken" dans gcc...


    sizeof (tab ) = 16 dans main() car c'est un tableau de 4 pointeurs
    Non: sizeof tab == 4 * sizeof(*char). Il y a des architectures où les deux coïncident, mais c'est loin d'être universel...

    sizeof (tab) =4 dans msg_intercept car c'est un pointeur.
    Idem: sizeof tab == sizeof(**char)
  • # Intérêt ?

    Posté par  . En réponse au message Creer un othllier en C. Évalué à 9.

    Ôte-moi un doute... Le but du TP, c'est de faire une étude comparative des bibliothèques de graphisme sous C, et de créer un programme au hasard pour l'utiliser et faire de jolis dessins, ou d'appliquer des règles de algorithmique/conception/développement/IA apprises en cours pour obtenir un programme qui marche ? En gros, il fait suite à un cours de prog graphique/conception d'IHM, ou un cours de programmation "classique"/algorithmique ?

    La réponse étant probablement la seconde, je dirai que, si tu n'as pas le temps d'étudier une bibliothèque graphique, et que les profs ne demandent pas de jolis zigouigouis de toutes les couleurs, tu peux rester en bête mode texte avec printf(). Ok, c'est pas joli, mais tu passeras ainsi plus de temps à bosser la conception générale du programme, l'IA (si c'est demandé de pouvoir jouer contre l'ordinateur), les algo/structures de données... C'est ce que j'ai fait quand j'ai dû faire un projet "othello" (c'était un projet en groupe, je précise). On est resté au bête printf(), on a fait une IHM basique mais fonctionnelle, et on a implémenté plusieurs niveaux difficultés (IA allant du naïf au alpha-beta avec nombre de demi-coups d'avance variable), en donnant la possibilité de faire jouer une IA contre une autre... Et ça fonctionnait !
    Et, si c'est ça qui t'intéresse, le prof nous a donné une bonne note: le programme répondait aux demandes (et même plus, vu qu'ils n'attendaient pas des IA aussi "poussées"), et la démo a marché sans bug, donc voilà.

    Cela dit, si tu es motivé/as le temps pour étudier une bibliothèque graphique ET répondre au reste du cahier des charges, alors les autres participants de ce forum t'indiqueront mieux que moi quelles bibliothèques sont dispo...

    Et, au passage, le printf()/fgets(), c'est super-portable ;) Même si les profs veulent essayer sur leur poste perso avec un OS exotique ou suranné, pour peu qu'ils aient un compilateur C, ça passe sans problème !