IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

conception d'un type texte


Sujet :

C

  1. #1
    Membre habitué
    Profil pro
    amateur
    Inscrit en
    Avril 2012
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : amateur
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2012
    Messages : 145
    Points : 144
    Points
    144
    Par défaut conception d'un type texte
    Bonjour,

    Je suis en train de créer une abstraction légère au-dessus des string / char* / char[] de C. C'est juste une
    struct {char * octets ; int count}(le détail est légèrement différent, mais le principe est là). Le but est de m'afrranchir de la myriade de problèmes, bogues, defauts mémoire et aussi certaines inefficacités dont la litérature à propos de C est remplie. Quelques avantages:

    * Le compte est toujours connu --> pas de param supplémentaire, pas d'appel strlen().
    * Pas de dépassement de tampon possible.
    * Peut stocker des caractères NUL.
    * Utilisation de fonctions mem* au lieu de str* (plus simple et efficace).
    * Pas de surallocation ; taille exacte.
    * Certains bound-checkings (*) deviennent inutiles (car on sait, en interne).
    * Possibilité de supprimer les autres bound-checkings pour la release (*).
    * Pas de problème de sécurité (par dépassement de tampon et tout ça).
    * Abstraction unicode / utf8 préparée.

    Désavantages:
    * Allocation sur le tas en général (questions sur le sujet à venir).
    * Un int/uint/size_t supplémentaire par objet.

    Connaissez-vous libmib? (http://www.mibsoftware.com/libmib/) Ils font plus ou moins ça sans stocker le compte. Donc il y a forcément des appels à strlen partout, mais la différence est que c'est abstrait par des fonctions (et non un type) d'un niveau légèrement supérieur à celles de string.h. Ils font ça avec des objets qui sont des char** et non des char*. Rusé, comme solution, mais je me demande si le coût (en complication, appels à strlen(), autres...) n'est pas supérieur au gain de stocker le compte et avoir une interface qui dit clairement ce qu'elle est et ce qu'elle fait.

    Alors voilà, j'ai plein de problèmes de conception et implémentation de ce truc-là. Comme certains sont indépendants (ou orthogonaux, comme disent les computer scientists ), je vais plutôt les aborder en plusieurs discussions, pour pas vous inonder. Le thème du jour : représentation d'un texte vide.

    1. Devrais-je représenter ça par {NULL, 0} ou par {pointeur_sur_chaine_vide, 0} ?

    Quelques réflexions :

    +++ Pas d'allocation du tout.
    +++ Les textes vides sont très courants.

    --- Impossible d'intéragir directement avec les routines C, du genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
           puts (texte.octets) ;    // segfault si texte vide
    Il faut donc traiter spécialement le cas texte vide à tout plein d'endroits.

    On ne peut pas laisser le code applicatif s'occuper de choses comme ça avec de tels bugs en puissance, et non détectés si les tests ne traitent pas le cas vide. Donc, il faut une interface qui fournit toutes ces fonctionnalités. Et même là, est-ce que la complication (interne) n'est pas un prix trop élévé à payer pour cette optimisation du cas texte vide ?
    Note: les langages "semi-bas-niveau" que je connais (comme D) font cette optimisation. (Aussi souvent pour des tableaux vides.)

    2. Est-ce qu'il devrait y avoir un unique objet texte vide ?

    Alors ça, c'est un drôle de point. Ca peut alléger largement le prog en temps et en espace. Et aussi faciliter et accélérer toutes les comparaisons avec le texte vide, du moins dans le cas où celui-ci n'est pas représenté par {NULL, 0} (auquel cas t_est_vide <=> t.octets == NUL)).

    PS: Je me rends compte que je suis en train de tomber en partie dans les pièges de l'optimisation prématurée . Alors je vais progresser avec la conception la plus simple et la plus claire. Mais ça n'empèche de penser et discuter par ailleurs. (En fait, prévoir des modifs / optimisations potentielles permet aussi de faciliter leur implantation si jamais... je crois).

    Merci de vos attention,
    Denis

    (*) Comment on dit bounds checking en français ? Et release ?

  2. #2
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 483
    Points : 13 684
    Points
    13 684
    Billets dans le blog
    1
    Par défaut
    Je me demande à quoi cela va te servir ?

    C'est pour réellement te créer une bibliothèque de gestion des chaines ou simplement pour tester une idée ?

    As tu déjà vu les GStrings ? http://developer.gnome.org/glib/2.30/glib-Strings.html

  3. #3
    Membre habitué
    Profil pro
    amateur
    Inscrit en
    Avril 2012
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : amateur
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2012
    Messages : 145
    Points : 144
    Points
    144
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Je me demande à quoi cela va te servir ?

    C'est pour réellement te créer une bibliothèque de gestion des chaines ou simplement pour tester une idée ?
    Ben, en fait les deux, plus poursuivre mon apprentissage de C en réalisant des choses utiles, potentiellement au moins. Mais au bout du compte j'ai besoin d'un type texte...

    ... qui ne peut pas réellement être la réutilisation d'un type existant pour des raisons d'interface et de fonctionnalité. Mais je peux m'inspirer de ce que d'autres ont fait de bien, d'où mon étude du 'astring' de la libmib évoquée plus haut, qui est la eule que j'aie vue de ce type (ils abstraient les problèmes sans avoir de struct qui contient le compte d'octets).

    A terme, ce type Texte serait un des types de base d'un projet de langage. La

    J'espère que j'ai répondu,
    Denis

  4. #4
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 483
    Points : 13 684
    Points
    13 684
    Billets dans le blog
    1
    Par défaut
    qui ne peut pas réellement être la réutilisation d'un type existant pour des raisons d'interface et de fonctionnalité.
    J'avoue ne pas avoir compris cette partie de ta phrase ^^

    Ben, en fait les deux, plus poursuivre mon apprentissage de C en réalisant des choses utiles, potentiellement au moins.
    J'aurais dit qu'il y avait des trucs plus fun à faire que de se prendre la tête à rajouter de l'abstraction aux chaines de caractères. Les chaines de caractères sont le point "sensible" en C, il faut faire avec sinon on choisit un autre langage ou on utilise des bibliothèques toutes faites et éprouvées.

    A terme, ce type Texte serait un des types de base d'un projet de langage.
    C'est ambitieux !

  5. #5
    Membre expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Points : 3 352
    Points
    3 352
    Par défaut
    Salut,

    J'ai plusieurs réflexions par rapport à tes posts :

    • C ou Pascal ?
      C'était une des guerres il y a une vingtaine d'années dont l'une des batailles opposait les strz (chaine à zéro terminal) et les lstr (chaine préfixée par la longueur).
      C a clairement fait le choix du strz, vouloir y utiliser les lstr va imposer de réécrire toutes les fonctions de base manipulant les chaines (tous les strXXX mais aussi les printf sans compter l'ajout d'une fonction de transformation pour pouvoir utiliser tes lstr là où C s'attend à une strz). C'est un sacré boulot, qui ne sera utile que s'il y a une forte plus value au bout.
    • 32 ou 64 bits ?
      Comme tu vas allouer de l'espace mémoire, la taille (count) sera idéalement un size_t, donc un entier non signé 32bit sur les architectures 32 bits, un entier non signé 64bit sur les architectures 64 bits (À moins de limiter la taille sur toutes les architectures, Pascal en 1990 n'avait que des chaines de 255 caractères par exemple).
    • charset ?
      Ce n'est généralement pas une bonne idée (si on manipule du texte) de vouloir garder le texte et son encodage, plusieurs encodages différents pouvant coexister. En effet, suivant l'encodage, le calcul de la longueur en symboles par exemple sera différent. Il est généralement plus efficace de choisir un encodage "interne" et de transcoder s'il le faut quand il le faut. Là il ne s'agit pas d'une optimisation précoce, mais d'un choix de conception.
    • allocation sur le tas = désavantage ???
      Mais on y reviendra plus tard.


    1. Devrais-je représenter ça par {NULL, 0} ou par {pointeur_sur_chaine_vide, 0} ?
    Bah ... c'est ta bibliothèque, tu fais comme tu le sens. Mais tu ne peux pas avoir de char* chaine_vide "", car cette chaine contient un unique \0, or dans ton implémentation une chaine peut contenir plusieurs \0 qui ne marquent en aucune façon une fin de chaine. Donc pour toi ta chaine vide est celle dont count=0 et peu importe que octet soit ou non alloué. De toute façon tu ne pourras jamais autoriser l'utilisation d'octets avec les fonctions c standards qui s'attendent à un strz.

    2. Est-ce qu'il devrait y avoir un unique objet texte vide ?
    Qu'est-ce que tu comptes manipuler ? Des struct, des pointeur sur des struct ? Qu'est-ce que tu comptes comparer ?

  6. #6
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 408
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 408
    Points : 23 800
    Points
    23 800
    Par défaut
    Citation Envoyé par Bktero Voir le message
    C'est ambitieux !
    Je plussoie !

    Ça part d'un bon sentiment et c'est un projet très excitant en soi, mais s'y jeter tête baissée, c'est encore un coup à tout abandonner.

    Citation Envoyé par denispir Voir le message
    Ben, en fait les deux, plus poursuivre mon apprentissage de C en réalisant des choses utiles, potentiellement au moins. Mais au bout du compte j'ai besoin d'un type texte...
    Oui, mais sache que lorsque tu auras suffisamment travaillé pour mener ton projet à bien, tu maîtriseras suffisamment les chaînes C traditionnelles pour ne plus avoir besoin de ton projet.

    Il y a une maladie chronique dans le monde du management et du développement dont on ne dira jamais assez les ravages qu'elle provoque : un individu survole une discipline ou un thème donné. Par manque d'information ou d'investissement, il ne la comprend pas ou — bien pire encore — ne la comprend qu'à moitié. Et au lieu d'essayer d'achever la lecture de la chose, il invente une nouvelle technologie « plus simple » à ses yeux, sans s'enquérir de l'état de l'art en la matière. Inévitablement, des écueils surgissent et l'individu ajoute à chaque fois des couches supplémentaires à son concept pour les contourner. Tant et si bien qu'au bout d'un moment, la technologie censée être plus simple devient un imbroglio inextricable. Ceci parce que s'étant complètement focalisé sur son projet, l'auteur s'est mis en tête de le mettre au point à tout prix plutôt que de remettre en cause l'hypothèse initiale et repartir sur de bonnes bases.

    C'est encore plus flagrant quand on a un manager qui estime pouvoir assimiler en un mois ce sur quoi planchent des ingénieurs confirmés depuis des années. J'ai vu en entreprise des petits joyaux développés par des gens consciencieux finir au rebut parce qu'un chef fraîchement arrivé, et probablement très respectable comme ailleurs, leur a d'emblée donné une suite de directives irréfléchies parce qu'il pensait à tort que son métier lui imposait justement de le faire.

    Faire une couche d'abstraction au-dessus des chaînes de caractères est effectivement justifié. Je l'ai d'ailleurs moi-même fait dans certains projets étudiants. Mais sache que tout, en C et dans la plupart des langages, a une raison d'être et, au moins, une histoire. Assure-toi de bien les connaître avant de conclure à une erreur de conception si tu comptes te lancer dans ce genre d'entreprise.

  7. #7
    Membre habitué
    Profil pro
    amateur
    Inscrit en
    Avril 2012
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : amateur
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2012
    Messages : 145
    Points : 144
    Points
    144
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    Je plussoie !

    Ça part d'un bon sentiment et c'est un projet très excitant en soi, mais s'y jeter tête baissée, c'est encore un coup à tout abandonner.
    [...]

    Il y a une maladie chronique dans le monde du management et du développement [...]

    Faire une couche d'abstraction au-dessus des chaînes de caractères est effectivement justifié. Je l'ai d'ailleurs moi-même fait dans certains projets étudiants. Mais sache que tout, en C et dans la plupart des langages, a une raison d'être et, au moins, une histoire. Assure-toi de bien les connaître avant de conclure à une erreur de conception si tu comptes te lancer dans ce genre d'entreprise.
    Je crois comprendre ce que tu veux dire et ce à quoi tu fais allusion (et si c'est bien le cas, j'approuve plutôt).

    Ceci dit, il y a dans de nombreux langages et particulièrement en C tout un tas d'aspects qui sont très largement considérés soit comme des erreurs, soit comme justifiés de certains points de vue mais par ailleurs sources de problèmes, voire de très graves problèmes.

    A la fois mon projet actuel et mon plaisir de programmer ne sont pas liés à rechercher l'efficacité maximale à tout prix (je dis bien à tout prix). En revanche, j'adore concevoir de chouettes abstractions claires, pratiques, qui permettent à l'utilisateur de dire ce qu'il veut dire aussi simplement que possible (càd sans en introduisant le minimum de complication atificielle) (et sans s'inquiéter de débordements de tampon, de terminateur NUL ou de portes d'entrées pour des bots malicieux).
    Bon, je suis pas seul à le dire, loin de là. Non seulement des programmeurs de très haut niveau ou des concepteurs de langages, mais des aussi établissements d'enseignement, des centres de recherches, des agences officielles (entre autres de sécurité) de divers pays... tiennent le même discours et parlent des mêmes problèmes (en C et/ou d'autres langages) (Je suis pê original, mais pas sur ce point-là!).
    Bien sûr, il y a une raison d'être pour le bas niveau de C. Mais rien n'empêche de bien circonscrire ce bas niveau à la fois dans le langage (avec une sorte de namespace, par exemple, ou de nommage distinct) et dans l'application en le restreignant aux endroits où les risques valent le coup (après profilage, disons). Etablir comme standard de fait (ou comme voie de moindre résistance) des instructions, types, fonctions très dangereuses et dont les avantages ne se manifestent que dans des cas particuliers bien identifiés, c'est... pas ce que j'ai envie de faire.

    Mais je fais une différence entre le langage comme outil pratique ou de plaisir, en général, et des projets ou explorations particuliers comme maintenant. Toutes ces histoires ne m'empêchent pas de m'amuser avec C, en ce moment, de découvrir tout un tas de pratiques, d'outils, et la communauté des programmeurs de ce langage que je trouve très chouette et conviviale.

    Denis

  8. #8
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 382
    Points : 41 588
    Points
    41 588
    Par défaut
    Ta décision de créer un nouveau type chaîne (parmi tant d'autres...) me rappelle un peu ce qui est fait avec les BSTR utilisées en Visual Basic ou en programmation Component Object Model (COM).

    Pour ta première question, une des règles de COM était que tout devait traiter NULL et une chaîne de taille zéro de la même manière. Un pointeur nul équivalait à une chaîne vide et était toujours une valeur valide. L'inconvénient de cela, c'est que le code doit toujours supporter le NULL sans planter, ce qui implique plus de tests, donc un code final un poil plus lent.

    Note aussi que les BSTR stockent la longueur dans le buffer alloué (le pointeur pointe juste après elle, en fait) plutôt qu'utiliser une structure.

  9. #9
    Membre habitué
    Profil pro
    amateur
    Inscrit en
    Avril 2012
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : amateur
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2012
    Messages : 145
    Points : 144
    Points
    144
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Ta décision de créer un nouveau type chaîne (parmi tant d'autres...) me rappelle un peu ce qui est fait avec les BSTR utilisées en Visual Basic ou en programmation Component Object Model (COM).

    Pour ta première question, une des règles de COM était que tout devait traiter NULL et une chaîne de taille zéro de la même manière. Un pointeur nul équivalait à une chaîne vide et était toujours une valeur valide. L'inconvénient de cela, c'est que le code doit toujours supporter le NULL sans planter, ce qui implique plus de tests, donc un code final un poil plus lent.
    Note que je fais pas ça seulement pour le plaisir, héhé. J'en ai aussi besoin. Mon projet ne peut tout simplement pas fonctionner avec des chaînes de base C, ni avec une librairie commune que je connaisse (j'en ai exploré plusieurs).
    Il me faut la longueur, du pur utf8, la possibilité de NUL inclus, et toutes les opérations communes & générales (donc, par exemple, je me fous totalement de tout ce qui classes prédéfinies ou casing, parce que c'est dépendant des scripts ou langages, ou même de conventions, come en français).
    D'autre part, les chaînes litérales doivent êtres décodées selon le codage du langage, pas celui de C. Par exemple pour inclure des codes unicodes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
        "Hello, #0041 0042 0043#"   // "Hello, ABC#"
    Et il y a des chaînes variables, comme en Cobra si vous connaissez de langage, du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
        write "Hello, {user_name}!"
    Note aussi que les BSTR stockent la longueur dans le buffer alloué (le pointeur pointe juste après elle, en fait) plutôt qu'utiliser une structure.
    Ca c'est intéressant. (C'est comme les chaînes de Pascal, je crois.)
    J'avais l'idée d'utiliser des indices basés sur 1 (pas de guegueres de religion, svp ). Si je stocke la longueur en début de zone allouée, alors les indices tombent juste (pas de i--).

    EDIT: Ah non, je me plante, il faudrait pour ça que les éléments de la chaîne aient la taile d'un pointeur. Or, je compte travailler en pur utf8 à la base.

    Sinon, quel est l'avantage de stocker la longueur dans la zone allouée pour les données, plutôt définir une struct?

    Denis

  10. #10
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 303
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 303
    Points : 4 967
    Points
    4 967
    Billets dans le blog
    5
    Par défaut
    Citation Envoyé par denispir Voir le message
    ...
    Sinon, quel est l'avantage de stocker la longueur dans la zone allouée pour les données, plutôt définir une struct?

    Denis
    Je m'insère dans la discussion.

    Créer une structure va forcément placer le compteur ainsi que les données dans la même zone allouée, non ?

  11. #11
    Membre habitué
    Profil pro
    amateur
    Inscrit en
    Avril 2012
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : amateur
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2012
    Messages : 145
    Points : 144
    Points
    144
    Par défaut
    Citation Envoyé par gerald3d Voir le message
    Je m'insère dans la discussion.

    Créer une structure va forcément placer le compteur ainsi que les données dans la même zone allouée, non ?
    Ben oui, c'est ce que je pensais. Et si p est un pointeur sur le début de la zone données, et n la taille de ton compteur, alors (type_compteur) p[-n] devrait te lire la taille. (Peut-être je raisonne mal...?) Mais ça me paraît inutile, car le compilo doit "décoder" tout ça, s.taille doit être strictement équivalent, moins l'indirection.
    Note: ce serait pas le cas avec des strings de taille variable, néanmoins, vu que les données ne seraient pas sur place.

    Denis

  12. #12
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 382
    Points : 41 588
    Points
    41 588
    Par défaut
    Il me semble que l'avantage est que tu n'as plus qu'un pointeur à manipuler, tu peux donc t'en servir pour des opérations atomiques (genre InterlockedCompareExchangePointer).

    La taille, tu l'obtiens généralement ainsi: size_t taille = ((size_t const*)p)[-1]; (bien sûr, encapsulé dans une fonction).

    Cela est indépendant de la décision d'accepter ou non les chaînes nulles.

    Au passage, note que pour raison de sécurité, COM rajoute toujours un \0 après le buffer, malgré que la taille soit indiquée. Je pense que c'est une bonne pratique.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Conception] Problème avec input type="text"
    Par adrix26 dans le forum PHP & Base de données
    Réponses: 8
    Dernier message: 02/03/2007, 11h52
  2. [Conception] valeur dans un input type text
    Par CYCLOPE91440 dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 10/02/2007, 19h08
  3. [access] champs type text sur un pc blob sur un autre
    Par Harry dans le forum Bases de données
    Réponses: 3
    Dernier message: 27/07/2004, 10h30
  4. Fonction LEFT sur champ de type "text" : méthodes
    Par MatthieuQ dans le forum Langage SQL
    Réponses: 4
    Dernier message: 08/06/2004, 12h15
  5. [UPDATE] Mise à jour d'un type text
    Par nico1492 dans le forum Langage SQL
    Réponses: 2
    Dernier message: 21/01/2004, 14h26

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo