Forum Programmation.c Probleme d'ecriture dans un STRUCT de int .

Posté par  .
Étiquettes : aucune
0
14
déc.
2006
Bonjour
je veux ecrire un petit prog de calcul sur des coordonnees 3D.

j'ai donc uns structure de ce type :

typedef struct
{
short x;
short y;
short z;
} point;
/* coordonnees pour chaque point */
point *p ;
point liste[NPI];

jusque la tout tout va bien
mais a l'execution d'un test (avant d'ecrire la suite)

je fais ca comme test precisement :
/* 1ere compile pour tester le mode de saisie */

for(i=0;i<NPI;i++)
{
scanf(" %d %d %d", &liste[i].x, &liste[i].y, &liste[i].z);
/* copie l'entr� dans la liste */
}
for(i=0;i<NPI;i++)
{
printf("\n %d %d %d", liste[i].x, liste[i].y, liste[i].z);
}


je rentre que des
1 2 3
4 5 6
7 8 9
10 11 12

et ainsi de suite

mais a la relecture (la seconde boucle )
le retour est

0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0

pourquoi donc ?
le scanf ne marche pas ?

merci de m'eclairer sur cette erreur de coding...
  • # Parentheses ?

    Posté par  (site web personnel) . Évalué à 2.

    Et si tu fais

    scanf(" %d %d %d", &(liste[i].x), &(liste[i].y), &(liste[i].z));

    Par reflexe je mets souvent des () on peut me dire que c'est inutile m'enfin au moins je suis sur de ce que fait le compilo ...
    • [^] # Re: Parentheses ?

      Posté par  . Évalué à 1.

      RAS de mieux ... comme prevu...
      j'utilise GCC comme compilo donc ANSI alors les parentheses forcees comme ca je me disais bien que ca servirai pas...mais il y avait de l'idee :)
  • # short

    Posté par  (site web personnel) . Évalué à 2.

    Et avec %hd au lieu de %d ?
  • # %hd

    Posté par  . Évalué à 2.

    %d sert à lire un 'int'. Pour un 'short', il faut utiliser %hd
    • [^] # Re: %hd

      Posté par  . Évalué à 1.

      Bon sang mais c'est ca...
      j'avais completement oublie ce detail tellement habitue a utiliser du long int...


      :)


      je teste de suite !!!
  • # Bizarre

    Posté par  (site web personnel) . Évalué à 2.

    Bizarre... j'ai pensé à un problème de format %d avec des short... mais en ayant copié ton code + de quoi le compiler... ça passe chez moi... (pourtant ça devrais pas, le short est sur deux octets et le int sur quatre).
    Mais quand même, vu la doc, essaie avec d'autres formats...

    Cf doc de scanf:
    À la suite du caractère % introduisant une conversion, il peut y avoir un nombre quelconque de caractères attributs de la liste suivante :
    ...
    h Indique que la conversion sera de type dioux ou n et que le pointeur suivant est un pointeur sur un short int (plutôt que sur un int).
    ...
    Les conversions suivantes sont disponibles :
    ...
    d Correspond à un entier décimal éventuellement signé, le pointeur correspondant doit être du type int *.
    ...


    [laurent@litchi badscan]$ gcc --version
    gcc-4.1.1 (GCC) 4.1.1 20060724 (prerelease) (4.1.1-3mdk)
    Copyright (C) 2006 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions. There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    #include <stdio.h>
    #define NPI 4

    typedef struct
    {
    short x;
    short y;
    short z;
    } point;

    /* coordonnees pour chaque point */

    point *p ;

    point liste[NPI];

    /* 1ere compile pour tester le mode de saisie */

    int main (int argc, const char** argv)
    {
    int i ;

    for(i=0;i<NPI;i++)
    {
    scanf(" %d %d %d", &liste[i].x, &liste[i].y, &liste[i].z);
    /* copie l'entr� dans la liste */
    }

    for(i=0;i<NPI;i++)
    {
    printf("\n %d %d %d", liste[i].x, liste[i].y, liste[i].z);
    }
    return 0 ;
    }



    [laurent@litchi badscan]$ ./a.out
    1 2 3
    4 5 6
    7 8 9
    10 11 12

    1 2 3
    4 5 6
    7 8 9
    10 11 12

    Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN

    • [^] # Re: Bizarre

      Posté par  . Évalué à 1.

      C'est bon le %hd passe sur ma version

      (je testai sur le macppc avec une vielle gcc 3.3.5 sous debian avec un powerbook
      sur le pc j'ai gcc 4.0.2 et oui ca passe...

      mais bon vu que le programme tournera sur des machines de collections (non PC)
      sur mac ppc mac68K et autres rognes je prefere forcer le format au cas ou...

      sinon je pourrai tjrs cross compiler !

      MERCI pour l'aide !!!!!
      • [^] # Re: Bizarre

        Posté par  . Évalué à 1.

        les x86 sont little-endian (les octets de poids faibles d'un "int" sont en 1er en mémoire), les power- sont en bigendian.
        Donc quand ton scanf ecrit dans ce qu'il croit etre un pointeur sur int, sur x86 il va écrire "octet 1 octet 2 octet 3 octet 4", qui vont ecrire sur "x" et "y". Sur power il va ecrire "octet 4 octet 3 octet 2 octet 1".
        Puis il va ecrire sur "y et z", puis sur "z et au dela".
        Sur tes tests avec de petites valeurs, octets 2-4 valent 0, et seul l'octet 1 contient entre 1 et 12.
        Avec les écrasements successifs des "%d %d %d" tu vas écrire dans x y z:
        "octet 1 octet 2 , 1 - 2, 1-2" sous x86 (qui a donc la chance de donner la meme valeur si elle etait < 65535) et "3-4, 3-4, 3-4" sous power (donc que des octets nuls)

        Si vous faisiez des tests avec comme valeur "65536", sous x86 la sortie ne donnerait que des 0, et sous power, que des 1.
    • [^] # Re: Bizarre

      Posté par  . Évalué à 2.

      Bizarre... j'ai pensé à un problème de format %d avec des short... mais en ayant copié ton code + de quoi le compiler... ça passe chez moi... (pourtant ça devrais pas, le short est sur deux octets et le int sur quatre).

      Ce n'est pas parce que ton programe est tombé en marche qu'il est correct ;)
      • [^] # Re: Bizarre

        Posté par  (site web personnel) . Évalué à 2.

        Tout à fait.

        Sauf que là je ne comprend pas pourquoi c'est "tombé en marche" :-)

        Faudrais désassembler, tout ça... autre chose à faire.

        Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN

        • [^] # Re: Bizarre

          Posté par  . Évalué à 3.

          Avec un peu de chance, si ton short fait bien 2 octets et ton int 4 (ce qui n'est pas obligatoire), il a écrit l'octet de poids faible au bon endroit (donc tu retrouves la bonne valeur), et les 3 autres dans un "ailleurs" qui n'est pas trop sensible pour ne pas planter le programme.
          Si ton int fait vraiment 4 octets, je soupçonne très fortement que, en raison de l'alignement mémoire de la structure, un des trois octets nuls est tombé sur l'octet de poids fort du short et les deux autres octets sont tombés dans la zone de bourrage.

          Quoi qu'il en soit, il s'agit très sûrement d'un comportement indéfini (je n'ai pas vérifié la norme) qui tombe en marche par miracle de l'alignement et de l'endianness.

          Il est aussi possible que sizeof(short) == sizeof(int) et alors on ne se pose même plus de question...
          • [^] # Re: Bizarre

            Posté par  (site web personnel) . Évalué à 2.

            Il est aussi possible que sizeof(short) == sizeof(int) et alors on ne se pose même plus de question...

            Pour ça, avec le GCC que j'ai testé, c'est sûr que non, j'ai vérifié hier soir en printfant les sizeof de int et de short.

            Par contre, une optimisation due à l'alignement des short tous les 4 octets... ça expliquerais bien la chose.

            Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN

  • # Et avec gcc...

    Posté par  (site web personnel) . Évalué à 4.

    gcc -Wall te retourne l'erreur ad-hoc.

    [laurent@litchi badscan]$ cc -Wall badscan.c
    badscan.c: In function ‘main’:
    badscan.c:25: warning: format ‘%d’ expects type ‘int *’, but argument 2 has type ‘short int *’
    badscan.c:25: warning: format ‘%d’ expects type ‘int *’, but argument 3 has type ‘short int *’
    badscan.c:25: warning: format ‘%d’ expects type ‘int *’, but argument 4 has type ‘short int *’

    Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN

  • # scanf ?

    Posté par  . Évalué à 3.

    Bizarre, personne n'a relevé...

    L'utilisation "propre" de scanf est très difficile, car les traitements d'erreur ne sont pas simples. Si une entrée ne respecte pas le bon format, alors scanf s'arrête sans "consommer" l'entrée standard. Si tu boucles sans vérifier le bon fonctionnement de scanf, et sans "consomer" toi-même l'entrée standard quand il y a une erreur, tu causes une boucle infinie de ton programme.

    La meilleure solution est de lire une ligne complète à la fois, puis de la traiter en mémoire. Pour celà, le mieux est d'utiliser une fonction qui encapsule fgets, comme ggets ( http://cbfalconer.home.att.net/download/index.htm ), et de traiter la chaîne de caractères résultante avec sscanf (ou strto*).

    Mais que tu utilises scanf ou sscanf (ou strto*), il est nécessaire de tester le bon fonctionnement de ces fonctions. Les *scanf renvoient le nombre de conversions effectuées avec succès (et strto* possède un argument spécifique). Tu dois donc effectuer le test :

        if (scanf(" %d %d %d", &liste[i].x, &liste[i].y, &liste[i].z) == 3)
        {
            /* traitement normal */
        }
        else
        {
            /* erreur ! */
        }


    Pour plus de détails, se référer à la FAQ de comp.lang.c, question 12.20 : http://c-faq.com/stdio/scanfprobs.html .

    De plus :
    printf("\n %d %d %d", liste[i].x, liste[i].y, liste[i].z);

    La sortie standard peut être bufferisée, donc place un "\n" en fin de la chaîne de format de printf, ou appelle fflush(stdout) pour vider l'éventuel tampon.

    PS: pendant que j'y suis, gcc -Wall -Wextra -std=<ton choix> -pedantic est ton ami (remplacer -Wextra par -W pour les versions inférieures à 4, je crois).
    • [^] # Re: scanf ?

      Posté par  (site web personnel) . Évalué à 2.

      Il n'y a aucune raison de ne pas utiliser scanf(3) dans le cadre d'un tel programme de test.

      pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.

      • [^] # Re: scanf ?

        Posté par  . Évalué à 2.

        Dans un programme de test, c'est vrai ; mais autant prendre de bonnes habitudes ;)

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.