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 :

affectation de tableau (taille fixe)


Sujet :

C

  1. #1
    Membre confirmé
    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
    Par défaut affectation de tableau (taille fixe)
    Bonjour,
    J'ai un drôle de problème d'affectation.

    Contexte: pour me détendre un peu , j'explorais la question d'un type numérique décimal et à virgule fixe (je veux dire "fixed-point", pas sûr du terme en français). Le codage est en BCD compressé, c'est-à-dire avec un chiffre par quartet. Chaque nombre est un entier non signé de 32 bits (type défini "Natural"), donc au max 8 chiffres. Bon, ça marche: je peux lire et écrire des nombres (facile en passant par l'ascci), et même faire des additions!
    Je me suis vite rendu compte que c'est super galère d'accéder à des chiffres dans un demi-octet, aussi bien en lecture qu'en écriture, même en-dehors des histoires de shift et masques, simplement les prendre l'un derrière l'autre, et dans l'ordre inverse en plus pour toute opération.

    Alors mon but là était de définir un type de nombre dans lequel sont distincts les quartets/chiffres: D'abord un type struct "Bidigit" de la taille d'un octet mais comprenant 2 digits "low" et "high" définis grâce aux champs de bits de C. Et du coup un Natural est un tableau fixe de 4 Bidigits.
    (Je voudrais aussi savoir quel est le coût en temps d'avoir une struct de 2 quartets comme ça, plutôt qu'un octet, et un tableau de 4 octets plutôt qu'un entier non-signé de 32 bits.)
    (J'ai aussi un itérateur de digits qui me les passe un par un pour les opérations : ça, ça marche, et c'est super pratique; mais il reste à accéder aux chiffres en écriture.)
    Les types de nombres sont comme ci-dessous, avec un example qui montre mon problème :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // type for a pair of digits in an octet
    typedef struct Bidigit {
       unsigned char high : 4 ;
       unsigned char low  : 4 ;
    } Bidigit ;
     
    // a natural is 4 bidigits
    typedef Bidigit Natural [4] ;
     
    int main () {
       Natural n1 = {{0,1},{2,3},{4,5},{6,7}} ;
       Natural n2 ;
       n2 = n1 ;      // ********** erreur ??? **********
       return EXIT_SUCCESS ;
    }
     
    ==>
     
    natural2.c:229:7: error: incompatible types when assigning to type ‘Natural’ from type ‘struct Bidigit *’
    Alors là, je pige plus rien. Je peux pas assigner un T à un T ?

    Denis

    PS: j'ai esayé juste pour voir de "caster" de force n1 en Natural, et ça me donne une erreur de gcc que je comprends pas non plus :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    int main () {
       Natural n1 = {{0,1},{2,3},{4,5},{6,7}} ;
       Natural n2 ;
       n2 = (Natural) n1 ;
       return EXIT_SUCCESS ;
    }
     
    ==>
     
    natural2.c:229:9: error: cast specifies array type
    Qu'est-ce que ça veut dire ? (Je comprends la lettre, mais pas le pourquoi du comment.)

    PPS : J'ai essayé de ruser, mias j'arrive pas à tromper gcc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    n2 = *((Natural*)(&n1)) ;
    ma donne la même erreur "incompatible types when assigning to type ‘Natural’ from type ‘struct Bidigit *’".

  2. #2
    Membre éprouvé Avatar de Flow_75
    Femme Profil pro
    Ingénieure
    Inscrit en
    Mai 2005
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieure
    Secteur : Transports

    Informations forums :
    Inscription : Mai 2005
    Messages : 1 104
    Par défaut
    Salut,

    Pour copier un tableau, tu dois faire élément par élément.

  3. #3
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    Je ne suis pas sûr de moi mais :
    Devrait marcher au moment de la déclaration de n2 non?

    Sinon, tu devrais essayer de définir un union :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    union
    {
          unsigned char;
          struct
          {
                unsigned char p1 : 4;// variable sur 4 bits?
                unsigned char p2 : 4;
           }moitie;
    }
    Ainsi si p1 et p2 sont contigües (faudra tester), tu pourras directement accéder à l'octet complet ainsi qu'aux deux demis-octets.

    Au pire si ceci ne marche pas, tu peux faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    union
    {
               unsigned long int; //ton entier de 32 bits
               unsigned char[4];//tableau de 4x8 bits
    }
    Et tu n'auras qu'à créer une fonction qui retourne le premier quartet (return x & 0F) puis une autre qui retourne le second quartet (return x << 4).

  4. #4
    Membre confirmé
    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
    Par défaut
    Citation Envoyé par Neckara Voir le message
    Je ne suis pas sûr de moi mais :
    Devrait marcher au moment de la déclaration de n2 non?
    Non, ça marche pas: "invallid initialiser". Et en castant vers Natural explicitement j'ai à nouveau "error: cast specifies array type".

    Sinon, tu devrais essayer de définir un union :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    union
    {
          unsigned char;
          struct
          {
                unsigned char p1 : 4;// variable sur 4 bits?
                unsigned char p2 : 4;
           }moitie;
    }
    Ainsi si p1 et p2 sont contigües (faudra tester), tu pourras directement accéder à l'octet complet ainsi qu'aux deux demis-octets.
    Hum, ça peut résoudre un problème à venir, mais c'est pas celui auquel je me heurte là.

    Au pire si ceci ne marche pas, tu peux faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    union
    {
               unsigned long int; //ton entier de 32 bits
               unsigned char[4];//tableau de 4x8 bits
    }
    Et tu n'auras qu'à créer une fonction qui retourne le premier quartet (return x & 0F) puis une autre qui retourne le second quartet (return x << 4).
    Voilà! Ca, c'est une idée... J'ai pas le réflèxe d'utiliser les unions pour changer de type (seulement quand il peut y avoir réellement plusieurs types de données). En fait, c'est un peu formaliser le genre de cast sauvage que je fais dans la première version de ce module.

    Merci beaucoup, je vais essayer et je ramène des pouvelles.
    Denis

  5. #5
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    1- on ne peut jamais écrire tableau = quelque chose. n2 n'est pas une lvalue (une expression qui désigne un objet)

    2- l'opérateur de cast ne peut s'appliquer qu'à un type scalaire

    3- n2 = *((Natural*)(&n1)) ; cf remarque 1 : n2 est de toute façon un tableau

    4-@Neckara :
    Je ne suis pas sûr de moi mais :
    Natural n2 = n1; Devrait marcher au moment de la déclaration de n2 non?
    Non.

  6. #6
    Membre confirmé
    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
    Par défaut ca roule !
    Voilà mon dernier type:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // type for a pair of digits in an octet
    typedef struct Bidigit {
       unsigned char high : 4 ;
       unsigned char low  : 4 ;
    } Bidigit ;
     
    // a natural will hold 4 bidigits
    typedef Bidigit Bidigits [4] ;
     
    // a natural is a union with a binary value so as to be able to copy directly
    typedef union Natural {
       Bidigits octets ;
       uint     binary ;
    } Natural ;
    Donc, je peux lire, écrite globalement (en binaire), ou chiffre par chiffre en utilisant pa exemple :
    Et je peux copier globalement le binaire d'un coup.

    Pour ceux que ça intéresse, voilà mon "énumérateur de chiffres", qui me facilite bien la vie:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    /// digit enumerator !!!
    typedef struct DigitsData {
       Natural n ;
       uint i ;
       bool end ;
       bool low_digit ;     // low (or high) digit in octet
    } DigitsData ;
    typedef struct DigitsData  * Digits ;
    Digits digits_new (Natural n) {
       Digits ds = malloc (1* sizeof(DigitsData)) ;
       VERIFY_MALLOC (ds) ;
       ds->n          = n ;
       ds->i          = digit_count ;
       ds->end        = false ;
       ds->low_digit  = false ;
       return ds ;
    }
    digit digits_next (Digits ds) {
       // Caller should stop the loop when ds->end is true:
       assert (! ds->end) ;
     
       // Step to next digit:
       ds->i -- ;
       uint i = ds->i ;
       ds->low_digit = ! ds->low_digit ;
       digit d ;
     
       // Read proper quartet in proper octet:
       if (ds->low_digit)   d = ds->n.octets[i/2].low ;
       else                 d = ds->n.octets[i/2].high ;
     
       // Possibly set flag end-of-enumeration:
       if (i == 0) ds->end = true ;
     
       return d ;
    }
    Ca s'utilise plus ou moins comme un énumérateur (itérateur) dans un langage de plus haut niveau ; ou plus ressemblant encore, comme pour parcourir une liste chaînée.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
       Digits ds = digits_new (n) ;
       while (! ds->end) {
       ...
       }
    Pour faire une opération, je crée les énumérateurs pour les deux opérandes et énumère en //.

    (Si l'énumérateur pouvait renvoyer un pointeur sue le chiffre au lieu de sa valeur, je pourrais énumérer le résultat, aussi, et écrire directement dedans ; mais c'est pas possible car un chiffre est un demi-octet. Donc je fais:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
          // Compute digit-wise sum, taking care of carry:
         ...
          // Store this digit sum into proper quartet:
          if (low_digit)    sum.octets[i_octet].low    = d ;
          else              sum.octets[i_octet].high   = d ;
    Merci encore,
    denis

  7. #7
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    @denispir
    Cette solution des champs de bits est non portable (comme pratiquement tout ce qui concerne les champs de bits) notamment parce que l'ordre des champs de bits n'est pas spécifié dans une unité de stockage

    n1256 :
    6.7.2.1 Structure and union specifiers
    ....
    4 A bit-field shall have a type that is a qualified or unqualified version of _Bool, signed int, unsigned int, or
    some other implementation-defined type.
    ....
    10 An implementation may allocate any addressable storage unit large enough to hold a bitfield.
    If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed
    into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is
    put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields
    within a unit (high-order to low-order or low-order to high-order) is implementation-defined
    . The alignment of
    the addressable storage unit is unspecified.

  8. #8
    Membre confirmé
    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
    Par défaut
    Citation Envoyé par diogene Voir le message
    @denispir
    Cette solution des champs de bits est non portable (comme pratiquement tout ce qui concerne les champs de bits) notamment parce que l'ordre des champs de bits n'est pas spécifié dans une unité de stockage

    n1256 :
    Sh*it! Mais je suis un peu gêné par leur formulation, là:

    Citation Envoyé par norme
    An implementation may allocate any addressable storage unit large enough to hold a bitfield.
    If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed
    into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is
    put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields
    within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of
    the addressable storage unit is unspecified.
    D'un côté ils disent:
    <<s'il ya assez de place, un champ de bits qui suite iimmédiatement un autre sera placé avec celui-ci dans la même unité (de stockage)>>
    De l'autre ils annoncent que l'ordre des champs de bits n'est pas garanti. C'est presque contradictoire, sauf qu'effectivement si tu définis 5+3 bits dans un octet ils pourraient s'amuser à l'empaqueter 3+5, mais quel intérêt (sauf te faire ch**er? ) ?

    Il me reste au moins 3 solutions, de toute façon:
    1. Je m'en fous, parce que c pas un projet important et viable à terme (du moins dans sa forme actuelle et pour mes prjets tels qu'ils sont)
    2. Je parie : come dans mon cas, les octets sont placés dans un tableau et donc dans l'ordre, ils ne reste que l'ordre des quartets/chiffre dans l'octet ; et comme ça fait 4+4, il faudrait vraiment être pervers pour l'inverser, non ?
    3. Maintenant que j'ai une interface pratique et propre, je peux réimplanter ça dans le détail. Par ex il me suffit de remplacer lecture/écriture d'octet par une paire de macros, ou de fct getter/setter (à inliner) qui ne font qu'un masque.

    D'ailleurs, c'est sûrement juste ça un champ de bits, non : une paire de mini-routines qui font un masque pour lire/écrire juste ces bit-là. Quelqu'un sait ça ?

    J'en profite pour poser une question (si quelqu'un suit bien j'aie clos cette discussion) : je me suis aperçu que les octets d'un nombre sont à l'envers (poids fort à droite, en dernier). Ainsi, si j'affiche le binaire de mon nombre en hexa, j'obtiens sa représentation, mais à l'envers (en fait ce sont pas les octets, mais les bits qui sont inversés, sinon les chiffres seraient dans l'ordre au sein des paires). Je sais jamais si c'est big- ou low-endian, ça. Mais quel est l'avantage selon vous?

    Denis

  9. #9
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    il faudrait vraiment être pervers pour l'inverser, non ?
    Je suppose qu'il a existé (ou qu'il existe encore) des machines pour lesquelles ceci se produisait et que c'est pourquoi la norme n'a pas jugé bon de spécifier (une norme c'est un compromis)

    D'ailleurs, c'est sûrement juste ça un champ de bits, non :...
    Je pense que les champs de bits ont été définis pour obtenir une possibilité bas-niveau du langage et s'adapter à des configurations spécifiques, par exemple des configurations de ports d'E/S, et que c'est pour cela que la portabilité est mal assurée. Je ne crois pas qu'ils soient initialement prévus pour le genre d'utilisation que tu en fais.
    Mais, je peux me tromper !

    Je sais jamais si c'est big- ou low-endian, ça. Mais quel est l'avantage selon vous?
    Il n'y en a pas, c'est une question d'adaptation au processeur de la machine et donc d'efficacité.

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

Discussions similaires

  1. Réponses: 5
    Dernier message: 15/03/2010, 13h22
  2. Tableau HTML taille fixe
    Par shuyun dans le forum Balisage (X)HTML et validation W3C
    Réponses: 7
    Dernier message: 28/08/2009, 16h35
  3. [HTML] Tableau avec Taille Fixe
    Par jamesleouf dans le forum Balisage (X)HTML et validation W3C
    Réponses: 5
    Dernier message: 21/05/2008, 15h42
  4. afficher descriptifs de tailles différentes dans un tableau de taille fixe
    Par poupouille dans le forum Balisage (X)HTML et validation W3C
    Réponses: 1
    Dernier message: 02/02/2008, 23h27
  5. [Tableau] Avoir des cases de taille FIXE!
    Par fayred dans le forum Mise en page CSS
    Réponses: 5
    Dernier message: 17/07/2007, 12h41

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