1

Erf, valà valà, j'ai un problème, fallait bien que ça arrive un jour, hein ? Bon ben je me suis donc attaqué au développement 64 bits (sur Atom 330, pour ceux qui ont suivis) et j'essaye -"autant-que-faire-se-peut"- à ce que mon build soit aussi bien compatible 32 bits que 64 bits (erf, je sais, je rêve éveillé). Je cherche à gommer AU MAXIMUM les différences, et j'y suis presqu'arrivé, sauf que :

  typedef struct{ // size, offset 32 bits, offset 64 bits
    int   nCount;    //  4,  0,  0
    short nMode;     //  2,  4,  4 <- ???
    sHue  sColor;    //  8,  8,  8
    char* pTest;     //  4, 16, 16
    char  aData[10]; // 10, 20, 24
  }sStack,*psStack;  // 28 (real) -> 32 (sizeof 32 bits), 40 (sizeof 64 bits)


Si on passe aData à 12, même si la struct ne fait 'que' 30, l'offset faisant la taille réelle passe à 32 (en 32 bits). En passant à 13, le sizeof passe à 36 (alignement de 4, version 32 bits). Bref voilà pour présenter le problème en général...

En particulier, je voudrais une struct de TOUJOURS la même taille, version 32 ou 64 bits, puisque je fais du message-passing. Donc derrière un client 32 bits il peut y avoir un serveur 64 bits, et inversement. Comme je ne veux PAS à connaître l'architecture en face (cliet ou serveur) il faudrait donc pouvoir fixer la taille des pointeurs à 8 octets. J'ai donc essayé ça :

#pragma pack(8)
  typedef struct{
[...]
  }sStack,*psStack;
#pragma pack()


Mais heu, ça marche pô : sur architecture 32 bits le compilateur 'caste' toujours les pointeurs sur 32 bits et le sizeof reste toujours à 32 :/ Non pas que je m'attende à ce qu'il passe à 40 (puisque nMode est encore 'casté' sur 4 octets -???-) mais au moins un sizeof à 36.

L'idée c'est de continuer à pouvoir utiliser ((psStack)buff)->pTest indifférement sur un build 32 bits ou 64 bits, sans avoir à caster, et surtout de pouvoir faire transiter une struct de toujours la même taille (le fameux buff qui reçoit un buffer quelconque). Les appels stdcall et cdecl doivent quand à eux rester les mêmes suivant la plateforme, donc proscription d'utiliser le switch /vmg par exemple. Je voudrais éviter le switch /Zp8 puisque je ne veux pas que toutes les struct soient affectées.

Bon je sais c'est pas forcément clair, mais si quelqu'un a une idée...

Kochise
avatar
Si Dieu m'a de nouveau fait homme, cette fois il m'a pas raté : marcher sur l'eau et dupliquer les pains, ça marche p'us :/

2

C'est marrant comme on peut trouver des solutions à la con... Je répète : A-LA-CON :

  typedef struct{ // size, offset 32 bits, offset 64 bits
    int   nCount;    //  4,  0,  0
    short nMode;     //  2,  4,  4 <- ???
    sHue  sColor;    //  8,  8,  8
    char* pTest;     //  4, 16, 16
    __declspec(align(8))
    char  aData[10]; // 10, 24, 24
  }sStack,*psStack;  // 28 (real) -> 40 (sizeof 32 bits), 40 (sizeof 64 bits)


Nan mais des fois... Mais allez comprendre ooh Seulement ça aurait été trop beau, ça ne marche pas sur tous les compilateurs, quelqu'un aurait un truc portable façon #pragma pack, mais qui fonctionne ?

Kochise
avatar
Si Dieu m'a de nouveau fait homme, cette fois il m'a pas raté : marcher sur l'eau et dupliquer les pains, ça marche p'us :/

3

Y a bien une solution crade : au lieu de mettre des pointeurs dans ta structure, tu mets des unions ( pointeur, uint_64 ), comme ça, tu es sûr que le champ fait bien 64 bits.
(par contre, tu espères réutiliser les pointeurs après ? hum )
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

4

oué même question, tu mets des pointeurs dans une structure qui se balade entre des bécanes différents? grin

5

Bah c'est pas illogique, je l'ai bien fait avec le Cell grin (sauf que dans ce cas, les pointeurs ne sont qu'à moitié invalides d'un cœur à l'autre tritop)

Sinon, les pointeurs correspondent peut-être qu'à des données locales, mais c'est toujours plus pratique d'avoir toutes les informations dans une seule structure.
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

6

Disons en fait, hrum, c'est assez compliqué. Evidement que les pointeurs 32 bits ne seront pas utilisés dans l'architecture 64 bits, c'est dans le but d'avoir un système suffisement homogène pour faire transiter les informations. Les pointeurs propres ne peuvent bien sûr qu'êtres utilisés localement. C'est surtout que dans l'optique d'un système client/serveur, imagine qu'un client 64 bits converse avec un serveur 32 bits et lui confie une structure avec un pointeur. Le serveur n'a pas accès à cette portion de la mémoire locale au client, par contre il existe un moyen de lui demander cette portion de mémoire par message-passing. Pour cela il lui faut être en mesure d'envoyer une requête avec le bon pointeur, en 64 bits. Je sais, c'est pô clair...

Pour faire simple, je suis en train d'écrire un linked-in driver en Erlang (d'où message-passing) sur mon Atom 330 (64 bits) et ma Via C7 (32 bits). Pour aller le plus vite possible dans les échanges SANS faire transiter des portions de mémoire j'utilise des structures avec pointeurs. C'est seulement QUAND le serveur à besoin de certaines données qu'il renvoie le handle correspondant (en fait le pointeur) sous forme de requête. A ce moment un échange de données brutes prend place.

C'est pourquoi j'ai IMPERATIVEMENT besoin que la struct source corresponde bit-à-bit à celle de destination, d'où essayer de simuler le packing d'une plateforme 64 bits sur une plateforme 32 bits. Ou alors il reste la solution de 'packer' la structure avec #pragma pack(1) avant de la faire transiter, évitant les octets de padding, mais ça rend la structure inutilisable d'un point de vu run-time (désalignement des données, alignment fault).

Kochise
avatar
Si Dieu m'a de nouveau fait homme, cette fois il m'a pas raté : marcher sur l'eau et dupliquer les pains, ça marche p'us :/

7

ahwé tu fais dans le niveau supérieur de balézure là
Kochise (./7) :
par contre il existe un moyen de lui demander cette portion de mémoire par message-passing

anéfé grin
Kochise (./7) :
Je sais, c'est pô clair...

sisi grin
Kochise (./7) :
je suis en train d'écrire un linked-in driver en Erlang

trilove rien qu'au nom ^^

j'ai tout compris en fait ^^

8

Et quel est le problème avec ma méthode (j'ai pas tout compris non plus triso )
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

9

Flanker (./3) :
Y a bien une solution crade : au lieu de mettre des pointeurs dans ta structure, tu mets des unions ( pointeur, uint_64 ), comme ça, tu es sûr que le champ fait bien 64 bits.
(par contre, tu espères réutiliser les pointeurs après ? hum )
Flanker (./8) :
Et quel est le problème avec ma méthode (j'ai pas tout compris non plus triso )

Je ne veux pas utiliser de casting, je veux pouvoir utiliser le pointeur directement quand il arrive avec un ((psStack)buff)->pTest qui va bien. Et de toute façon même si je casta (Leatitia ?) le pointeur, ça change pas le problème qu'il n'y a PAS QUE le problème de taille des données qui change entre 32 et 64 bits, mais leur alignement aussi : http://docs.hp.com/en/5966-9844/ch03s02.html

Ducoup même si je forçais (Leatitia ?) le pointeur sur un __int64, il risquerait de ne pas se trouver à la même place suivant les membres précédents. Rhâââââaaa...

Kochise
avatar
Si Dieu m'a de nouveau fait homme, cette fois il m'a pas raté : marcher sur l'eau et dupliquer les pains, ça marche p'us :/

10

Ça me fait vaguement penser à ça : http://www.ibm.com/developerworks/forums/message.jspa?messageID=13984211#13984211

Son problème est justement d'aligner les données sur 16o, mais tu devrais pouvoir étendre sa méthode, non ?
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

11

squalyl (./7) :
Kochise (./7) :
je suis en train d'écrire un linked-in driver en Erlang

trilove rien qu'au nom ^^

j'ai tout compris en fait ^^

C'est whachement simple pourtant :

http://www.erlang.org/doc/tutorial/c_portdriver.html
http://weblog.hypotheticalabs.com/?p=446

Un port-driver est plus safe, mais plus lent et plus compliqué :

http://dawsdesign.com/drupal/erlang-driver-walkthrough

Kochise
avatar
Si Dieu m'a de nouveau fait homme, cette fois il m'a pas raté : marcher sur l'eau et dupliquer les pains, ça marche p'us :/

12

Je pense que ce que tu cherches à obtenir est fondamentalement impossible à faire proprement en C...

Le standard C garantit que dalle sur la représentation interne des structures. Rien que la possibilité de "packer" les structures ne fait pas partie du standard, et sa syntaxe diffère complètement entre VC++ et GCC. Et même si tu arrives à bricoler quelque chose qui fonctionne, je ne pense pas que t'aies de garantie que çà restera le cas pour les versions futures des mêmes compilos...

(et ne parlons même pas du problème de l'endianness)
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

13

Flanker (./10) :
Ça me fait vaguement penser à ça : http://www.ibm.com/developerworks/forums/message.jspa?messageID=13984211#13984211

Son problème est justement d'aligner les données sur 16o, mais tu devrais pouvoir étendre sa méthode, non ?

Aligner les données de la struct sur 16 octets se fait comme ça :

typedef __declspec(align(16)) struct{
  [...]
}sStack,*psStack;


Ducoup ta struct est alignée en mémoire sur un multiple de 16. Moi j'ai besoin que TOUS les membres se trouvent strictement à la même place, qu'importe si la struct est alignée par multiple de 4 sur une architechture 32 bits, ou multiple de 8 sur du 64 bits. C'est un bloc de mémoire qui non seulement DOIT avoir la même taille, mais aussi la même disposition interne et être directement utilisable (sans casting) sur les deux plateformes.

"Une fois de plus, je dois t'en demander de trop, Harry..." (c) Dumbledore. Tiens, la citation colle bien à la situation

Kochise
avatar
Si Dieu m'a de nouveau fait homme, cette fois il m'a pas raté : marcher sur l'eau et dupliquer les pains, ça marche p'us :/

14

Kochise (./6) :
C'est pourquoi j'ai IMPERATIVEMENT besoin que la struct source corresponde bit-à-bit à celle de destination, d'où essayer de simuler le packing d'une plateforme 64 bits sur une plateforme 32 bits. Ou alors il reste la solution de 'packer' la structure avec #pragma pack(1) avant de la faire transiter, évitant les octets de padding, mais ça rend la structure inutilisable d'un point de vu run-time (désalignement des données, alignment fault).

Bah, les char pad[7] sont toujours efficaces…
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

15

Zerosquare (./12) :
Je pense que ce que tu cherches à obtenir est fondamentalement impossible à faire proprement en C...

Disons que le compilo Microsoft permet de jouer un peu : http://msdn.microsoft.com/en-us/library/83ythb65(VS.80).aspx (regarde à la fin)
Zerosquare (./12) :
(et ne parlons même pas du problème de l'endianness)

Peut être en demandant à FLC ? Naaaan, la private joke de fou, j'abuse trop là wink Disons c'est dans ce cas précis qu'on se rend finalement compte de la supériorité du little endian sur le big endian ! J'explique :

  typedef struct{
    int   nCount;
    short nMode;
    sHue  sColor;
    char* pTest; // 4 ou 8 octets suivant l'architechture
    char  aData[10];
  }sStack,*psStack;


Imagine qu'on accède donc à la struct avec un ((psStack)buff)->pTest bien senti, mais que pTest à été casté sur un __int64 (genre avec un __declspec(align(8)) ou tout autre option de compilation). Suivant l'endianesse sur une machine 32 bits (on cherche pas en 64 bits, forcément) où se situe REELEMENT le pointeur ? En little endian à pTest, en big endian à pTest+4 ! Du coup pour éviter les casting et les prises de tête inutiles, le little endian offre bien une supériorité à commencer par l'octet de poid faible se situant toujours à la même adresse...

Kochise
avatar
Si Dieu m'a de nouveau fait homme, cette fois il m'a pas raté : marcher sur l'eau et dupliquer les pains, ça marche p'us :/

16

Kochise (./15) :
Imagine qu'on accède donc à la struct avec un ((psStack)buff)->pTest bien senti, mais que pTest à été casté sur un __int64 (genre avec un __declspec(align(8)) ou tout autre option de compilation). Suivant l'endianesse sur une machine 32 bits (on cherche pas en 64 bits, forcément) où se situe REELEMENT le pointeur ? En little endian à pTest, en big endian à pTest+4 ! Du coup pour éviter les casting et les prises de tête inutiles, le little endian offre bien une supériorité à commencer par l'octet de poid faible se situant toujours à la même adresse...


C'est justement l'intérêt du little endian wink
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

17

Kevin Kofler (./14) :
Kochise (./6) :
C'est pourquoi j'ai IMPERATIVEMENT besoin que la struct source corresponde bit-à-bit à celle de destination, d'où essayer de simuler le packing d'une plateforme 64 bits sur une plateforme 32 bits. Ou alors il reste la solution de 'packer' la structure avec #pragma pack(1) avant de la faire transiter, évitant les octets de padding, mais ça rend la structure inutilisable d'un point de vu run-time (désalignement des données, alignment fault).

Bah, les char pad[7] sont toujours efficaces…

Ouaip, sauf que j'utilise des struct d'une librairie que c'est pas moi qui l'a faite. Donc j'aimerais autant que possible pouvoir utiliser la déclaration de la struct sans avoir à la modifier (et donc recompiler la librairie, pour peu que j'ai le code source) mais pouvoir faire dialoguer mon driver avec des struct de même taille de chaque coté de la liaison (le travail avec la lib se fait en stdcall nativement suivant la plateforme, donc que la struct soit plus ou moins grosse à cause des padding introduits par le compilo ne pose pas problème). Merci quand même pour ta proposition, j'y avais pensé en dernier recours...

Microsoft conseille l'usage de #pragma pack(1) et de __unaligned : http://msdn.microsoft.com/en-us/library/ms253935.aspx

Sinon ils conseillent à : http://msdn.microsoft.com/en-us/library/aa448596.aspx

"In such cases, you can still use packed structures if you also carefully unpack members of a packed structure before using data in the program. This technique might involve copying the data in a structure member-by-member, or element-by-element, or field-by-field, into a temporary location that is correctly aligned."

Justement ce que je veux éviter à tout pris !

Kochise
avatar
Si Dieu m'a de nouveau fait homme, cette fois il m'a pas raté : marcher sur l'eau et dupliquer les pains, ça marche p'us :/