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 :

Questions sur l'alignement des adresses


Sujet :

C++

  1. #1
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 23
    Points : 21
    Points
    21
    Par défaut Questions sur l'alignement des adresses
    Bonjour,

    j'ai vu que certaines architectures comme SPARC ne tolèrent pas les accès non-alignés, donc je souhaite les éviter complètement, voulant produire du code portable. Toujours voulant produire du code portable, je souhaite travailler avec des octet et non des byte (même si c'est la même chose dans la majorité des cas).

    Or:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    uint32_t buffer[ 16 ];
    std::ifstream file("mon_fichier.bin");
    file.read(reinterpret_cast <char*> (buffer), 64);
    Ce code ne peut il pas poser doublement problème ?
    1. Si j'ai compris le principe de l'alignement, on va ici écrire des bytes au milieu d'un uint32_t.
    2. on extrait des bytes (la méthode read est faite ainsi) !!! donc j'hypothèse que si un byte fait 9bits sur mon système, en remplissant le buffer je vais écrire 64 fois 9 bits = 576 bits alors que j'aurais voulu écrire 64 * 8 bits = 512 bits: dépassement. catastrophe. sans compter que ça sera pas aligné comme je le souhaite. Je suis confus parce que wikipedia indique que même si uint32_t par exemple fait 32 bits, il est aussi garanti qu'il fasse 4 bytes... si le byte est plus gros, y a-t-il bourrage ? mais dans ce cas, j'aurais pas des soucis en voulant bricoler à l'intérieur, en faisant un décalage par exemple ?


    EDIT:
    Si problème il y a effectivement, une solution pourrait être d'utiliser carrément un std::basic_istream <uint32_t> au lieu de std::istream (qui utilise des char).
    Seulement cela suppose pour moi de convertir un ifstream par exemple (càd un istream) en basic_istream <uint32_t>. je vais tester mais je ne sais pas encore ce que ça implique...

    mais y a-t-il effectivement un problème ?

    EDIT2: uint32_t est remplacé par unsigned int ....

  2. #2
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 371
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    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 371
    Points : 23 626
    Points
    23 626
    Par défaut
    J'ai tendance à penser que si tu t'en soucies au niveau de ton code, c'est que justement celui-ci n'est pas portable. Ces choses devraient être du ressort du compilateur.

    Sinon, plus précisément, je n'ai pas travaillé assez longtemps sur SPARC pour connaître ses méthodes d'accès (c'est mal, je sais) mais j'ai tendance à penser que s'il numérote ses adresses mémoire en octets, tu dois pouvoir sans peine lire des octets individuels à n'importe quelle position. C'est le fait de lire d'un coup un mot de 16 ou 32 de bits à une adresse non multiple qui le fera tilter. Sinon, si ladite architecture numérote directement des mots de 32 bits, alors tu ne pourras pas du tout lire un octet individuellement. Tu seras obligé de lire le mot entier qui le contient, puis l'extraire à l'aide d'opérations logiques et de décalage. Note que c'est déjà ce que tu fais lorsque tu veux extraire des champs de longueur inférieure à huit bits.

    Note également que ce travail est fait pour toi (au niveau de l'octet en tout cas) par les microprocesseurs type x86, mais rien n'empêche le compilateur de faire ce travail lui-même, mais il est surtout beaucoup plus probable que le compilateur n'ait même pas s'en soucier car le format d'adressage utilisé par le C sera quasi-forcément celui du micro-processeur.

    En effet, le C spécifie d'un côté que 1 char = 1 byte et, d'un autre côté, qu'un char est un type entier suffisamment large pour représenter le jeu de caractères de base utilisable pendant l'exécution d'un programme (lequel tient largement dans huit bits).

    Étant donné que le C se laisse une certaine liberté dans le format de ses entiers (lesquels, sur le même principe, doivent simplement être suffisamment grands pour être capables de représenter une plage de nombres donnée), c'est surtout si tu travaillais sur un micro-processeur 4 bits que le C déterminerait qu'un char tiendrait sur deux mots binaires. Ça ne l'empêcherait pas d'utiliser des pointeurs utilisant le format du micro-processeur quand même, et l'alignement ne serait pas une nécessité.

    Par contre, il est très peu probable que le compilateur définisse des types dont la longueur n'est pas multiple de celle des mots binaires et vice versa. Par exemple, si tu travailles sur une architecture 12 bits (cas des PIC 12Cxxxx, par exemple), il y a de fortes chances pour que 1 char = 1 mot de douze bits, lesquels mots sont adressés un à un comme le sont les octets sur les architectures plus classiques (on aurait éventuellement pu imaginer que le compilo fasse l'effort de définir un char sur 6 bits, par exemple, mais le basic execution character set qu'il doit pouvoir représenter contient 91 caractères, donc six bits ne seraient pas suffisants, de toutes façons).

  3. #3
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 23
    Points : 21
    Points
    21
    Par défaut
    Justement si, c'est pas souci de portabilité que je cherche à travailler sur des Octets. En effet, md5 travaille sur des blocks de 512 bits soit 16 mots de 32bits. Donc je cherche à m'assurer de ne pas utiliser de type de donnée inadapté.

    Mais je vais t'illustrer mon propos:

    architecture avec byte de 8bit en big endian:
    (11223344)h = (10001001000000000000000000000000)b
    architecture avec byte de 9bits en big endian:
    (11223344)h = (100010010000000000000000000000000000)b ???

    Alors; si je caste un tel nombre en tableau de byte, et que j'accède au premier élément, je me retrouve avec:
    cas 1:
    (10001001)b = (11)h
    cas 2:
    (100010010)b = (112)h

    Est-ce que je me trompe ?

  4. #4
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 371
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    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 371
    Points : 23 626
    Points
    23 626
    Par défaut
    Citation Envoyé par unomadh Voir le message
    Mais je vais t'illustrer mon propos:

    architecture avec byte de 8bit en big endian:
    (11223344)h = (10001001000000000000000000000000)b
    architecture avec byte de 9bits en big endian:
    (11223344)h = (100010010000000000000000000000000000)b ???
    Euh… j'ai du mal à voir comment tu arrives à de telles valeurs. Quelle que soit l'architecture utilisée et le nombre de bits dans un byte, l'hexadécimal n'est qu'une forme de représentation d'un nombre, dans laquelle un chiffre hexadécimal correspond à exactement quatre bits. Donc, ici :

    (11223344)h = (00010001001000100011001101000100)b … en big endian.

    Maintenant, si je décompose ce nombre en mots de 8 ou 9 bits, j'obtiens :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    00010001 00100010 00110011 01000100
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    00000010 001001000 100011001 101000100
    Donc, trois bits de padding supplémentaires dans le mot de neuf bits de poids fort. À noter que les zéros non significatifs du MSB sur huit bits peuvent être considérés au même titre comme du padding.

    Alors; si je caste un tel nombre en tableau de byte, et que j'accède au premier élément, je me retrouve avec:
    cas 1:
    (10001001)b = (11)h
    cas 2:
    (100010010)b = (112)h
    Tu ne peux pas caster un nombre vers un tableau. Et dans ce cas précis, tu ne castes pas un nombre en tableau de bytes, tu transtypes le pointeur. La manière dont le nombre est stocké en mémoire est directement dépendante de l'architecture (donc, pas portable). Si tu veux aller les chercher directement, il faudra donc tenir compte de ses caractéristiques toi-même.

    Si tu veux faire quelque chose de réellement portable, il faut utiliser les types dont la longueur est un diviseur de 512 (ce sera généralement une puissance de 2). Si ce n'est pas possible, tu fais un tableau d'entiers de la longueur disponible de ton choix, jusqu'à ce que le nombre total égale ou excède 512. Tu fais tes calculs naturellement dessus, et tu fais un & logique sur le MSB pour éliminer les bits surnuméraires.

  5. #5
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 23
    Points : 21
    Points
    21
    Par défaut
    D'accord, je comprend bien ta solution. Je te remercie pour toutes ces informations !

    Entre temps j'ai terminé mon implémentation de md5 qui est à peine plus lente que md5sum (quelques secondes pour un fichier de 5 Gio) donc bon ... je suis déjà content de moi, même si je ne vois pas comment faire baisser encore cette durée. J'ai voulu tenter le coup avec OpenMP mais je ne suis même pas sûr que ça soit possible (chaque opération nécessitant le résultat de la précédente, difficile à priori de paralléliser)

    Mais ça, c'est une toute autre histoire

    Encore merci

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

Discussions similaires

  1. [FLASH 8] Question sur la portée des objets.
    Par i_shinji dans le forum Flash
    Réponses: 1
    Dernier message: 02/11/2005, 17h18
  2. Question sur la gestion des fenetres MDI
    Par RémiONERA dans le forum C++Builder
    Réponses: 6
    Dernier message: 06/07/2005, 07h58
  3. question sur le rafraichissement des données dans la base
    Par vbcasimir dans le forum Bases de données
    Réponses: 8
    Dernier message: 06/06/2005, 12h44
  4. question sur le comportement des threads
    Par rose-bonbon dans le forum CORBA
    Réponses: 4
    Dernier message: 27/10/2004, 18h00
  5. question sur le format des images ..
    Par vbcasimir dans le forum Langages de programmation
    Réponses: 7
    Dernier message: 28/08/2003, 12h08

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