Partage
  • Partager sur Facebook
  • Partager sur Twitter

Alignement des structures C# - C++

Sujet résolu
    16 avril 2018 à 14:22:50

    Bonjour à tous,

    J'ai un problème d'alignement des structures et je les reprends donc une par une pour analyser d'où vient ce problème. Ceci étant fait, il persiste quelques questions à ce sujet :

    1) J'ai cru comprendre qu'une fonction dans une struct n'était pas à prendre en compte quant à la taille totale de la struct.
    Si cela est vrai, comment est-ce possible ? Ne faut-il pas la stocker quelque part ? Comment peut-elle reconnue si aucune mémoire ne lui est allouée ? Qui dit données dit place mémoire non ?

    2) J'utilise des tableaux de char pour réaliser cet alignement. D'un point de vue "conventions" ou "propreté", comme vous voudrez, y'a-t-il un problème à utiliser cette méthode des deux côtés (oui, ça peut paraître étrange comme question... :euh:) ? Ou l'on préfèrera fixer l'une par rapport à l'autre sans trifouiller l'autre en question ?

    3) Dans le cas d'un mauvais alignement, passer en paramètre un objet de type struct A dans un struct B (ou vice-versa) où sizeof(A) > sizeof(B), que ce passe-t-il ?
    Les données sont elles tronquées dans un cas, et à moitié rempli de null dans l'autre ?

    Vous remerciant de votre aide

    -
    Edité par Sillimon 16 avril 2018 à 14:39:22

    • Partager sur Facebook
    • Partager sur Twitter
      16 avril 2018 à 15:13:06

      Sillimon a écrit:

      Bonjour à tous,

      J'ai un problème d'alignement des structures et je les reprends donc une par une pour analyser d'où vient ce problème. Ceci étant fait, il persiste quelques questions à ce sujet :

      1) (a)J'ai cru comprendre qu'une fonction dans une struct n'était pas à prendre en compte quant à la taille totale de la struct.
      Si cela est vrai, (b)comment est-ce possible ? (c)Ne faut-il pas la stocker quelque part ? (d)Comment peut-elle reconnue si aucune mémoire ne lui est allouée ? (e)Qui dit données dit place mémoire non ?

      (a)C'est tout à fait vrai...

      (b)pour faire simple,

      1. Parce que la notion de structure et de fonction n'existe plus dans le code binaire exécuté par le processeur: il n'y a plus que des adresses mémoire, et leur contenu
      2. parce que les fonctions ne sont pas stockées directement dans les structures: ce sont de bonnes vieilles fonctions libres (comme en C) qui prennent, comme premier paramètre, un pointeur sur la structure à laquelle elles appartiennent, qui est gentiment ajouté (sans rien dire) par le compilateur

      (c) Bien sur que les fonctions sont stockées quelque part, mais pas là où tu crois ;)

      (d)parce que l'appel à une fonction, quand on regarde le code binaire exécutable (ou l'assembleur, plus compréhensible) se limite à

      1. mettre quelques informations dans la pile d'exécution
      2. mettre quelques informations dans différents registres
      3. modifier l'adresse de la prochaine instruction à exécuter

      Bien sur, c'est très simplifié pour la compréhension, mais c'est dans l'ensemble correct ;)

      strong>(e)Tout à fait, mais les instructions et les données sont à des endroits différents dans le programme final ;)

      2) (a)J'utilise des tableaux de char pour réaliser cet alignement. D'un point de vue "conventions" ou "propreté", comme vous voudrez, (b)y'a-t-il un problème à utiliser cette méthode des deux côtés ? (c)Ou l'on préfèrera fixer l'une par rapport à l'autre sans trifouiller l'autre en question ?

      (a)Depuis l'arrivée de C++17, nous préférerons utiliser std::byte parce qu'il ne traine pas derrière lui cette notion fallacieuse d'être associé à un symbole susceptible d'être affiché.

      (b)tu peux travailler avec des tableaux de char (ou plutôt de byte) des deux cotés, mais tu dois veiller à travailler sur des copies: il ne faudrait pas que tes modifications apportées d'un coté provoque des problèmes de l'autre ;)

      (c) cf (b)

      3) Dans le cas d'un mauvais alignement, passer en paramètre un objet de type struct A dans un struct B (ou vice-versa) où sizeof(A) > sizeof(B), que ce passe-t-il ?
      Les données sont elles tronquées dans un cas, et à moitié rempli de null dans l'autre ?

      deux cas sont possibles, par convention j'appellerai "source" la structure contenant les données "d'origine" et "destination" celle qui contient le résultat de la conversion 

      soit sizeof(source) < sizeof(destination) : il n'y a pas de problème "majeur", si ce n'est que les bytes "en trop" ne seront pas forcément modifiés (et qu'il pourront donc contenir des "anciennes valeurs").

      Soit sizeof(source) > sizeof(destination): Alors là, il y a un gros problème...  Car, si tu copie l'intégralité de la source dans la destination, il y a "une partie" des bytes de la source qui... n'a pas sa place dans la destination, mais qui devra bien aller "quelque part" (on parle de "débordement").

      Et ce quelque part sera toujours l'espace mémoire qui vient "juste après" celui qui est destiné à recevoir les données de ta destination.  La question à $ 200 000, c'est: quelles sont les données qui se trouvent dans cet espace mémoire? Car, elles seront irrémédiablement modifiées pour représenter les "valeurs qui n'entraient pas dans la destination".

      Et ca, ca peut occasionner quelques résultats... pour le moins surprenants ;)

      • Partager sur Facebook
      • Partager sur Twitter
      Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
        16 avril 2018 à 15:13:20

        1) une fonction prend de la mémoire, mais pas dans la structure. La fonction est en mémoire avec le reste du code exécutable de ton application, pas avec la mémoire utilisée par l'exécution de ton programme.

        Tu parles de données, quel rapport avec les fonctions ?

        2) osef de l'alignement des données. (Plus précisément, vu ta question 1, tu n'as pas les connaissances en architecture des ordis et des systèmes pour utiliser correctement l'alignement). Laisse le compilateur gérer ca, ne fais pas d'alignement a la main.

        3) Si A et B n'ont aucune relation entre elles, ne fais pas ca. Peu importe leur alignement.

        A mon avis, vu les questions que tu poses, il y a un gros problème de compréhension du code bas niveau. Et, sauf si tu as une raison tres particuliere de te poser ce genre de questions, ce n'est pas de choses a faire.

        EDIT : pas forcément d'accord avec la réponse de koala. Sans savoir pourquoi tu veux faire ca, c'est clairement casse gueule et donner la moitié des infos est pire.

        struct A {
            int i { 0 };
            char dummy[2];
        };
        
        struct B {
            double d { 0.0 };
        };
        
        void foo(B@); // @ = pointeur, reference, valeur ?
        
        A a;
        foo(a); // ???

        Si je comprends bien la question, il veut faire quelque chose comme ca. Sauf cas très particulier, ca sent tres mauvais comme code. Surtout s'il n'a pas les connaissances de base sur le fonctionnement bas niveau (ce qui semble etre le cas vu la question 1).

        Moi je dis danger.

        -
        Edité par gbdivers 16 avril 2018 à 15:22:42

        • Partager sur Facebook
        • Partager sur Twitter
          16 avril 2018 à 16:03:08


          Merci beaucoup à tout les deux pour ces informations claires et précises comme je les aiment !

          gbdivers a écrit:

          2) osef de l'alignement des données. (Plus précisément, vu ta question 1, tu n'as pas les connaissances en architecture des ordis et des systèmes pour utiliser correctement l'alignement). Laisse le compilateur gérer ca, ne fais pas d'alignement a la main.

          C'est tout à fait vrai vrai, j'ai de très faibles connaissances du sujet mais, à moins que je me trompe, dans mon cas, je n'ai pas d'autres choix que de le faire à la main. Travaillant sur un mix de C# - C++/CLI (J'appel une fonction de mydll.cpp à partir de mon .cs). Le compilateur saura-t-il faire l'allocation mémoire différente dû aux différentes tailles de chaque type ?

          Et, dans le cas où l'on possède les connaissances requises, quel est l'intêret de le faire à la main si le compilateur peut effectivement effectuer cela tout seul ?

          gbdivers a écrit:

          3) Si A et B n'ont aucune relation entre elles, ne fais pas ca. Peu importe leur alignement.

          A mon avis, vu les questions que tu poses, il y a un gros problème de compréhension du code bas niveau. Et, sauf si tu as une raison tres particuliere de te poser ce genre de questions, ce n'est pas de choses a faire.

          EDIT : pas forcément d'accord avec la réponse de koala. Sans savoir pourquoi tu veux faire ca, c'est clairement casse gueule et donner la moitié des infos est pire.

          struct A {
              int i { 0 };
              char dummy[2];
          };
          
          struct B {
              double d { 0.0 };
          };
          
          void foo(B@); // @ = pointeur, reference, valeur ?
          
          A a;
          foo(a); // ???

          Si je comprends bien la question, il veut faire quelque chose comme ca. Sauf cas très particulier, ca sent tres mauvais comme code. Surtout s'il n'a pas les connaissances de base sur le fonctionnement bas niveau (ce qui semble etre le cas vu la question 1).

          Moi je dis danger.


          A et B sont les mêmes struct mais dans des langages différents.

          Tu te méprends cependant, je sais très bien que ce n'est absolument pas la chose à faire (et je n'essaye pas d'arriver à  ce résultat, j'y suis juste malencontreusement arrivé à cause d'une bête erreur dans mes FieldOffSet. Je me doutais déjà du résultat de la question 2) et 3). Je trouve ça juste intéressant de savoir, dans le cas où ce serait fait, quel genre de mouise on peut créer.

          Pour la question 1), je n'ai pas d'excuses :-° Mais j'en sais désormais plus grâce aux explications de koala (et les tiennes mais, t'ayant lu quelques secondes plus tard, j'ai eu le droit à un récap)



          -
          Edité par Sillimon 16 avril 2018 à 16:07:36

          • Partager sur Facebook
          • Partager sur Twitter
            16 avril 2018 à 16:14:35

            Sillimon a écrit:

            mais dans des langages différents

            Et ca ne te semblait pas etre une information a preciser avant ? (Le titre n'est pas assez clair, vu que koala et moi n'avons pas pensé a ca)

            Le problème est que tu pars sur des problèmes de comportements potentiellement différents de plusieurs compilateurs et langages. C'est encore plus casse gueule. Qui te dit que l'un des compilateurs ne va pas ajouter d'autres choses sur ta structure ? Que le nombre de bytes d'alignement sera le même ?

            Je passe mon tour sur cette question, je ne connais pas assez le C# (a mon boulot, on passe par une interface C pour faire le lien entre la lib C++ et le C#). Mais c'est très casse gueule si tu ne connais pas les spécificités de ton compilateur C++ ET celles de ton compilateur C#.

            • Partager sur Facebook
            • Partager sur Twitter
              16 avril 2018 à 17:06:41

              gbdivers a écrit:

              Sillimon a écrit:

              mais dans des langages différents

              Et ca ne te semblait pas etre une information a preciser avant ? (Le titre n'est pas assez clair, vu que koala et moi n'avons pas pensé a ca)

              Mea culpa, il est vrai que j'aurais dû le préciser dans la description du problème également.

              gbdivers a écrit:

              Le problème est que tu pars sur des problèmes de comportements potentiellement différents de plusieurs compilateurs et langages. C'est encore plus casse gueule. Qui te dit que l'un des compilateurs ne va pas ajouter d'autres choses sur ta structure ? Que le nombre de bytes d'alignement sera le même ?


              Ajouter d'autres choses ?

              Je pense que les FieldOffSet sont justement là pour "réguler" l'alignement. J'ai pu réussi à accorder la taille de chaque struct en comptant la taille de chaque champ, tout semble ok de ce côté. Je me renseignerai néanmoins plus en détails sur les spécificités de mes deux compils pour éviter les problèmes à l'avenir ^^

              Merci beaucoup de vos explications à tout les deux, tout est bien plus clair !



              -
              Edité par Sillimon 16 avril 2018 à 17:08:47

              • Partager sur Facebook
              • Partager sur Twitter
                16 avril 2018 à 18:06:39

                Comme je l'ai dit, je connais pas trop C#, donc les "FieldOffSet" me parle pas beaucoup. Mais en C++, tu as des fonctions dédiées pour l'alignement http://en.cppreference.com/w/cpp/memory/align (et aliganas, alignof, etc). C'est peut etre une piste a regarder pour faire un alignement un peu plus propre.

                Mais ta question est tres specifique du coup, attend l'intervention d'une personne plus competente que moi sur ce type de problematiques.

                • Partager sur Facebook
                • Partager sur Twitter
                  6 juin 2018 à 18:44:44

                  Une "struct" en C# n'a pas le même sens qu'en C ou en C++.

                  Une "struct" C# est plus proche d'une "struct" C que C++ sur bien des points.

                  Étant donné que vous utilisez du C++/CLI, je vous conseille d'utiliser celui-ci pour faire l'interface entre le monde managé du C# et le monde natif C/C++/whetever.

                  Pouvez-vous être plus explicite avec votre C# et votre ".cpp", avec un exemple ?

                  Parce que j'ai l'impression que c'est un faux problème.

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.

                  Alignement des structures C# - C++

                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                  × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                  • Editeur
                  • Markdown