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

Bibliothèque standard C Discussion :

printf et argments en linux


Sujet :

Bibliothèque standard C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 42
    Par défaut printf et argments en linux
    Bonjour,

    Désolé si j'aborde un sujet déjà traité, mais ma recherche sur le forum n'a rien donné.

    J'ai un cas concret sur Linux en C avec printf en 2 lignes.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
      #include <stdio.h>
     
      int main(int nArgCount, char **sArguments) {
        printf("#DEBUG: essai '%s', '%s'\n", "p1", "p2");
        printf("#DEBUG: essai '%s', '%s'\n", "p1");
     
        return 0;
      }
    A l'exécution j'ai comme affichage:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
      #DEBUG: essai 'p1', 'p2'
      #DEBUG: essai 'p1', 'p2'
    Strange. Je dirais même plus: pas terrible

    Le compilateur est gcc 4.2.3 (un récent).

    Là où je veux en venir, c'est que j'ai écrit une fonction qui utilise stdarg.h (avec les f(a/u)meuses macros va_start, va_arg et va_end) et je cherche un moyen simple de déterminer le nombre d'arguments passés à la fonction (définie avec quelques paramêtres et '...').

    L'idée étant de détecter d'anciennes valeurs passées afin de ne prendre en compte que les nouvelles (ie: dans mon exemple l'argument 'p2' du 2è printf serait détecté comme une ancienne valeur).

    J'ai quelques menues idées, mais voudrais savoir comment vous procédriez

    PluX59

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 398
    Par défaut
    Le plus simple, c'est de mettre une valeur sentinelle, comme dans execl() : Le dernier paramètre doit toujours être un pointeur nul...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 398
    Par défaut
    Note: Un gcc bien réglé te donnera un avertissement sur le code que tu as posté...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 42
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Le plus simple, c'est de mettre une valeur sentinelle, comme dans execl() : Le dernier paramètre doit toujours être un pointeur nul...
    Effectivement, c'est une solution... C'est celle que j'ai retenue en dernier recours...

    C'est comme celle d'indiquer le nombre d'arguments avant la déclaration variadique...

    J'en suis arrivé à creuser le business de stockage des variables dans la pile pour effacer leur contenu (ie: des pointeurs sur chaines ou des valeurs directes de type int et compagnie) au fur et à mesure de la lecture de mes valeurs.

    Parce que c'est bien ce boulot là que ne font pas les fonctions __builtin_va_arg des compilos (aliasés par va_arg et les autres macros définies par stdarg.h).

    Je pensais plutôt à des solutions 'logicielles' (ie: garder une trace des précédents appels...) ou 'brutales' (comme celle que j'ai citée précédemment)...

    PluX59

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 398
    Par défaut
    Fais gaffe, les solutions "brutales" risquent de tomber sur un os si le compilo fait certaines optimisations auxquelles tu n'avais pas pensé... (surtout gcc).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  6. #6
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Par défaut
    Citation Envoyé par PluX59 Voir le message
    Strange. Je dirais même plus: pas terrible

    En fait, c'est classique.

    Le premier appelle à printf empile les pointeurs p1 et p2. Puis il y a dépilement (sans suppression !)
    Le deuxième appelle empile juste p1 (mais le pointeur sur p2 est toujours là).
    printf voit qu'il doit écrire 2 arguments, il regarde là où doit être p1 et regarde ensuite au pointeur suivant sur la pile (il y a toujours un pointeur vers p2)

    Et donc ça affiche "p1" "p2" deux fois.

    Mais si le dépilement mettait 0 à tous les coups, ça planterait bien.

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 42
    Par défaut
    Citation Envoyé par millie Voir le message
    En fait, c'est classique.

    Le premier appelle à printf empile les pointeurs p1 et p2. Puis il y a dépilement (sans suppression !)
    Le deuxième appelle empile juste p1 (mais le pointeur sur p2 est toujours là).
    printf voit qu'il doit écrire 2 arguments, il regarde là où doit être p1 et regarde ensuite au pointeur suivant sur la pile (il y a toujours un pointeur vers p2)

    Et donc ça affiche "p1" "p2" deux fois.

    Mais si le dépilement mettait 0 à tous les coups, ça planterait bien.
    Merci pour les explications, j'avais bien compris l'effet de bord...

    Par contre quand tu dis que ça planterait bien... Je préfère nuancer en disant que c'est pas prévu pour que ça ne plante pas dans ce cas là.

    Personnellement, dans le cas que je traite, je comptais sur la détermination du nombre d'arguments ou sur le fait qu'à partir du dernier argument on me retournait une valeur NULL pour sortir de ma fonction...

    Pourquoi le code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    printf("#DEBUG: essai '%s', '%s'\n", 'P1");
    n'afficherait-il pas simplement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    #DEBUG: essai 'P1', '%s'
    ?

    Ca me semble logique pour un code cloisonné... Ici ça n'est pas le cas, d'où mon "pas terrible"

    Pour l'instant l'ajout d'un <NULL> en dernier paramêtre d'appel est encore la solution la moins couteuse en temps et la plus propre, effectivement...

    PluX59

  8. #8
    Membre éclairé Avatar de trax44
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    300
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 300
    Par défaut
    ben en fait tu fais quelques <<~d'anormale~>> => conséquence <<~anormale~>

    après commence par un gcc -Wall quand tu compiles ou encore plus marrant -Werror (cf man gcc)

    C'est juste que, de base, gcc laisse passer beaucoup de choses.

  9. #9
    Expert confirmé

    Inscrit en
    Août 2006
    Messages
    3 971
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 3 971
    Par défaut
    Jeo,
    Citation Envoyé par PluX59 Voir le message
    Pourquoi le code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    printf("#DEBUG: essai '%s', '%s'\n", 'P1");
    n'afficherait-il pas simplement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    #DEBUG: essai 'P1', '%s'
    Tu lui demandes d'afficher deux chaînes, pourquoi voudrais-tu qu'il ne t'en affiche qu'une ?

    Comme l'a rappelé Médinoc, il faut bien régler ton compilateur, et tenir compte de ce qu'il te raconte.

  10. #10
    Rédacteur
    Avatar de Vincent Rogier
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    2 373
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 2 373
    Par défaut
    Citation Envoyé par PluX59 Voir le message

    Là où je veux en venir, c'est que j'ai écrit une fonction qui utilise stdarg.h (avec les f(a/u)meuses macros va_start, va_arg et va_end) et je cherche un moyen simple de déterminer le nombre d'arguments passés à la fonction (définie avec quelques paramêtres et '...').
    les macros de la famille va_xxx n'ont aucune idées du nombre d'argument.

    En C, toute les fonctions à nombre de paramètres variable doivent se baser un des paramètres fournis pour déterminer le nombre d'argument :
    • chaine de caractères de type format avec n identifiants (libc)
    • paramètre numérique précisant le nombre d'arguments
    • sentinelle
    Il n'y a pas d'autres possibilités....

    PS : La sentinelle (pointeur nul) présente le défaut de pouvoir être confondue avec un argument qui peut être un pointeur null...
    Vincent Rogier.

    Rubrique ORACLE : Accueil - Forum - Tutoriels - FAQ - Livres - Blog

    Vous voulez contribuer à la rubrique Oracle ? Contactez la rubrique !

    OCILIB (C Driver for Oracle)

    Librairie C Open Source multi-plateformes pour accéder et manipuler des bases de données Oracle

Discussions similaires

  1. Débat : quelle distribution Linux choisir pour débuter ?
    Par Anonymous dans le forum Distributions
    Réponses: 227
    Dernier message: 18/02/2015, 10h09
  2. [socket-pthread-linux]printf non executé
    Par sebatlante dans le forum C
    Réponses: 4
    Dernier message: 11/04/2011, 11h34
  3. [NASM / Linux][Débutant] Segmentation fault affichage avec printf
    Par donkeyquote dans le forum x86 32-bits / 64-bits
    Réponses: 4
    Dernier message: 02/11/2008, 19h00
  4. OmniORB : code sous Windows et Linux
    Par debug dans le forum CORBA
    Réponses: 2
    Dernier message: 30/04/2002, 17h45
  5. Je ne peux établir une connexion cliente sous Linux.
    Par Anonymous dans le forum CORBA
    Réponses: 5
    Dernier message: 16/04/2002, 15h57

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