Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Unchecked_Conversion versus C cast

79 views
Skip to first unread message

slos

unread,
Mar 20, 2013, 10:04:49 AM3/20/13
to
Bonjour,

Dans mon domaine, la communication industrielle, on passe son temps à gérer des messages.

Généralement, ces messages sont composés d'un en-tête (header) fixe, et d'une charge variable en fonction de la commande ou de l'indication, etc...

En C, on reçoit donc un message qui a une structure générique, un en-tête et un tas d'octets, et on colle sur ce tas d'octets une structure en "castant" le pointeur sur le tas de données en un pointeur sur la structure du corps du message.

Remarquez que l'on reconsidère les mêmes données sous un autre angle, sans recopie des données.

En Ada, je ne vois que Unchecked_Conversion pour faire la même chose, mais il y a recopie des données.

Or, les messages peuvent avoir une taille de 1500 octets et là ça me semble rédhibitoire question performance.

Soit je n'ai rien compris, c'est ma foi fort possible, soit il y a une autre méthode que j'ignore encore.

Merci d'avance pour vos réponses.

Cordialement,
Stéphane
http://slo-ist.fr/ada4autom

gautier...@hotmail.com

unread,
Mar 20, 2013, 10:29:46 AM3/20/13
to
Pas sûr qu'il y ait forcément de copie avec Ada.Unchecked_Conversion:

RM 13.9 (12):
"An implementation may return the result of an unchecked conversion by reference, if the Source type is not a by-copy type. In this case, the result of the unchecked conversion represents simply a different (read-only) view of the operand of the conversion."

Maintenant, pour être sûr de ne pas avoir de copie, il y a ceci:
for x'Address use y'Address;
Exemple ici:
http://unzip-ada.sf.net/za_html/zip__adb.htm#618_13

Cela dit, cela vaut la peine de faire une estimation coût/bénéfice de passer par un "cast": c'est évidemment plus rapide, mais il pourrait y avoir de gros plantages au mauvais moment.
Tout dépend de la fréquence de ces messages et de la performance des ordinateurs.
L'avantage d'un méthode "propre" serait une meilleure détection d'erreurs lors de la phase de test.
_________________________
Gautier's Ada programming
http://gautiersblog.blogspot.com/search/label/Ada
NB: Pour une réponse directe, adresse e-mail valable par le lien ci-dessus

slos

unread,
Mar 20, 2013, 11:11:01 AM3/20/13
to
Merci pour votre réponse.

A propos du RM, le côté "propre à l'implémentation" me gène un peu, le côté (read-only) également. Il arrive qu'il faille retourner le même paquet modifié.

Quant à l'usage de X'Address, on me l'a souvent déconseillé en Ada et j'avoue que je ne sais pas trop quand il faut utiliser un access ou une adresse. Des fois ça marche et des fois pas... Il faut dire que ma langue maternelle en informatique est le C et que le concept d'adresse / pointeur y est central.

Dans :

SE_Buffer : Stream_Element_Array (1 .. buffer'Length);
for SE_Buffer'Address use buffer'Address;
pragma Import (Ada, SE_Buffer);

Vous indiquez d'utiliser comme adresse du SE_Buffer celle du buffer mais il n'a pas le même type. Permettez que je m'en étonne et vous en demande l'explication.

Je connaissais l'usage de pragma Import pour C. Il faut que j'arrive à comprendre ce que fait ce même pragma avec Ada...

Je ne comprends pas trop l'acharnement des Adaïstes contre le C et le C++.

Je pratique accessoirement les trois langages et on peut écrire des âneries avec les uns comme avec les autres.

Il y a des tas de concepts que j'aime en Ada et j'aimerais que l'on insiste davantage sur ceux-ci que sur la sûreté du langage vis à vis de ses "concurrents".

Ludovic Brenta

unread,
Mar 20, 2013, 4:32:34 PM3/20/13
to
Pour ma présentation au FOSDEM, j'ai fait usage pour la première fois
d'un type variant avec Unchecked_Union pour représenter le type
"évenement" du système X. Voici ce type:

type Detail_T (Response_Type : Response_Type_T := Reply) is record
case Response_Type is
when Button_Press | Button_Release | Motion_Notify =>
Detail : Button_T;
when others =>
Padding : Interfaces.Unsigned_8;
end case;
end record
with Unchecked_Union;

type Response_T (Sent : Boolean; Response_Type : Response_Type_T) is record
Detail : Detail_T (Response_Type);
Sequence : Interfaces.Unsigned_16;
case Response_Type is
when Button_Press | Button_Release | Motion_Notify =>
Time : Interfaces.Unsigned_32;
Root : XCB.Window.T;
Event : XCB.Window.T;
Child : XCB.Window.T;
Root_X : Interfaces.Integer_16;
Root_Y : Interfaces.Integer_16;
Event_X : Interfaces.Integer_16;
Event_Y : Interfaces.Integer_16;
State : Interfaces.Unsigned_16;
Same_Screen : Interfaces.Unsigned_8;
Pad_Button : Interfaces.Unsigned_8;
when Configure_Notify =>
Configure_Event_Window : XCB.Window.T;
Configured_Window : XCB.Window.T;
Above_Sibling : XCB.Window.T;
X, Y : Interfaces.Integer_16;
Width, Height, Border_Width : Interfaces.Unsigned_16;
Override_Redirect : Interfaces.Unsigned_8;
Pad_Configure : Interfaces.Unsigned_8;
when others =>
Pad_Others_2 : String (1 .. 4*6);
Full_Sequence : Interfaces.Unsigned_32;
end case;
end record;
for Response_T use record
Sent at 0 range 7 .. 7;
Response_Type at 0 range 0 .. 6;
end record;

Les discriminants Sent (1er bit, de poids fort) et Response_Type (les 7
bits suivants) déterminent quels autres composants existent dans la
Response. L'aspect Unchecked_Union, appliqué au type Detail_T, indique
que le discriminant Detail_T.Response_Type n'est pas un composant de
Detail_T (ici, c'est un composant et un discriminant du type qui le
contient: Response_T).

Les discriminants peuvent déterminer, par exemple, la taille d'un
tableau, donc le type variant n'a pas nécessairement une taille fixe
(les événements X ont une taille fixe mais c'est un détail).

Avec cette technique on peut écrire:

type Message (discriminants ...) is record
...
end record;
type Message_Access is access all Message;

function Next_Message return Message_Access;
pragma Import (C, Next_Message, "next_message");

Message : Message_Access;
begin
loop
Message := Next_Message;
exit when Message = null;
Process (Message);
end loop;


(Pour ceux que ça intéresse, les sources complètes sont disponibles sous
licence GPLv3 ou ultérieure ici:

http://www.ada-france.org:8081/branch/changes/org.ludovic-brenta.xcb
)

--
Ludovic Brenta.

slos

unread,
Mar 20, 2013, 5:03:59 PM3/20/13
to
Merci pour cette suggestion.

J'ai déjà étudié cette solution avec discriminants et unions mais je ne suis pas convaincu.

En C il est également possible de déclarer des unions, mais ce n'est pas ce qui est fait lorsque les unions sont susceptibles d'exploser.

On détermine un en-tête donc, fixe, et un tas d'octets dont la taille maximale est fixée, ce que l'on appelle un paquet.

On définit ensuite une ribambelle de messages qui rentrent tous dans ce schéma.

Si l'on définissait une union, elle serait tout simplement énorme.

L'ajout d'un message ou une modification quelconque obligerait à recompiler tout le code dépendant.

Il se trouve que la société dans laquelle j'officie développe des dizaines de piles de protocoles, et tous les messages tiennent dans ce même paquet.

Quelle autre solution meilleure qu'un AdaCast dans ce cas ?

Cordialement,
Stéphane

gautier...@hotmail.com

unread,
Mar 21, 2013, 8:15:58 AM3/21/13
to
Le mercredi 20 mars 2013 16:11:01 UTC+1, slos a écrit :

> Dans :
>
> SE_Buffer : Stream_Element_Array (1 .. buffer'Length);
> for SE_Buffer'Address use buffer'Address;
> pragma Import (Ada, SE_Buffer);
>
> Vous indiquez d'utiliser comme adresse du SE_Buffer celle du buffer mais il n'a pas le même type. Permettez que je m'en étonne et vous en demande l'explication.

Il s'agit d'une astuce de détypage comme Unchecked_Conversion (mais garantie sans copie). A utiliser avec précaution, donc.
G.
__
PS: en l'occurrence, il y a un test pour vérifier si les types sont compatibles:

subtype Size_test_a is Byte_Buffer(1..19);
subtype Size_test_b is Ada.Streams.Stream_Element_Array(1..19);
workaround_possible: constant Boolean:=
Size_test_a'Size = Size_test_b'Size and
Size_test_a'Alignment = Size_test_b'Alignment;

slos

unread,
Mar 21, 2013, 11:52:16 AM3/21/13
to
Je vois que cela permet d'utiliser deux tableaux d'octets qui ne diffèreraient que par leur type déclaré avec la même adresse.

Dans le cas qui m'occupe, j'ai un tableau d'octets et une ou plusieurs structures. Est-ce que votre astuce peut être utilisée ?

Je ne comprends pas ce que fait :
pragma Import (Ada, SE_Buffer);

Auriez vous un pointeur sur la documentation correspondante ?

Merci !

gautier...@hotmail.com

unread,
Mar 22, 2013, 6:04:22 AM3/22/13
to
> Dans le cas qui m'occupe, j'ai un tableau d'octets et une ou plusieurs structures. Est-ce que votre astuce peut être utilisée ?

Si les tailles du tableau et des structures, et au niveau du contenu, les alignements et les questions de petit/gros-boutiste coïncident, j'imagine que tout devrait bien marcher.

> Je ne comprends pas ce que fait :
> pragma Import (Ada, SE_Buffer);

Très bonne question. J'ai repris la clause et le pragma sur la recommendation d'un Adaïste distingué:

http://groups.google.com/d/msg/comp.lang.ada/1CJv_eIpCww/4E2mBmLJluMJ

et j'ai été trop paresseux pour me renseigner sur le rôle du pragma.
En cherchant "pragma import for address clause", il semble que ce soit pour empêcher une éventuelle initialisation de SE_Buffer.

G.

J-P. Rosen

unread,
Mar 22, 2013, 6:58:06 AM3/22/13
to
Le 20/03/2013 16:11, slos a �crit :
> Je ne comprends pas trop l'acharnement des Ada�stes contre le C et le
> C++.
Il n'y a pas d'acharnement, mais il faut bien comprendre de quoi on
parle, et s�parer C de C++ qui sont des langages tr�s diff�rents.

C a �t� d�fini comme un "assembleur portable", et c'est un excellent
langage puisqu'il correspond parfaitement � son cahier des charges. Ada
a �t� con�u comme un langage de haut niveau. En gros, C est le meilleur
langage pour programmer un ordinateur, mais Ada est le meilleur langage
pour d�velopper une application informatique.

Ce qui irrite un peu les ada�stes, c'est de voir tant de gens se
cramponner au niveau "programmation de la machine" au lieu de prendre le
recul et la vue de plus haut niveau qu'autorise Ada.

Le probl�me de C++ est tr�s diff�rent; c'est un tr�s gros langage (la
norme est plus grosse d'1/3 que la norme Ada!), et il souffre de
contradictions entre son d�sir d'�tre un langage de haut niveau et son
h�ritage syntaxique du C. Si C est clairement un "assembleur portable"
(et fait �a tr�s bien), C++ est un "assembleur portable orient� objet",
et l� j'estime qu'il y a un gros probl�me de placement s�mantique.

> Je pratique accessoirement les trois langages et on peut �crire des
> �neries avec les uns comme avec les autres.
Bien s�r, et en tant que consultant, j'ai parfois vu de l'Ada absolument
horrible (�crit par des gens qui n'avaient manifestement pas eu de
formation ad�quate).

La question est plut�t de savoir si on peut �crire des choses propres
dans les diff�rents langages. Et ce qui me g�ne avec C (et encore plus
avec C++ qui devrait s'en affranchir), c'est qu'il est impossible
d'oublier la repr�sentation concr�te des �l�ments et d'avoir une vue
r�ellement abstraite. Ex: on ne peut ignorer qu'un cha�ne de caract�res
n'est qu'un pointeur sur le premier �l�ment!

--
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr

gautier...@hotmail.com

unread,
Mar 22, 2013, 10:56:53 AM3/22/13
to
> Je ne comprends pas ce que fait :
> pragma Import (Ada, SE_Buffer);
>
> Auriez vous un pointeur sur la documentation correspondante ?

Un complément: en omettant le pragma, GNAT GPL 2012 dit ceci:

use pragma Import for "SE_Buffer" to suppress initialization (RM B.1(24))

Le verset 24 de B.1 dit:

"The declaration of an imported object shall not include an explicit initialization expression. Default initializations are not performed."

G.

slos

unread,
Mar 22, 2013, 12:37:05 PM3/22/13
to
Merci beaucoup pour vos explications et votre patience.
Je prendrai le temps d'étudier cela.

Bon week end !

Cordialement,
Stéphane
http://slo-ist.fr/ada4autom

slos

unread,
Mar 22, 2013, 12:43:22 PM3/22/13
to
Le vendredi 22 mars 2013 11:58:06 UTC+1, J-P. Rosen a écrit :
> Le 20/03/2013 16:11, slos a écrit :
>
> > Je ne comprends pas trop l'acharnement des Adaïstes contre le C et le
>
> > C++.
>
> Il n'y a pas d'acharnement, mais il faut bien comprendre de quoi on
>
> parle, et séparer C de C++ qui sont des langages très différents.
>
>
>
> C a été défini comme un "assembleur portable", et c'est un excellent
>
> langage puisqu'il correspond parfaitement à son cahier des charges. Ada
>
> a été conçu comme un langage de haut niveau. En gros, C est le meilleur
>
> langage pour programmer un ordinateur, mais Ada est le meilleur langage
>
> pour développer une application informatique.
>
>
>
> Ce qui irrite un peu les adaïstes, c'est de voir tant de gens se
>
> cramponner au niveau "programmation de la machine" au lieu de prendre le
>
> recul et la vue de plus haut niveau qu'autorise Ada.
>
>
>
> Le problème de C++ est très différent; c'est un très gros langage (la
>
> norme est plus grosse d'1/3 que la norme Ada!), et il souffre de
>
> contradictions entre son désir d'être un langage de haut niveau et son
>
> héritage syntaxique du C. Si C est clairement un "assembleur portable"
>
> (et fait ça très bien), C++ est un "assembleur portable orienté objet",
>
> et là j'estime qu'il y a un gros problème de placement sémantique.
>
>
>
> > Je pratique accessoirement les trois langages et on peut écrire des
>
> > âneries avec les uns comme avec les autres.
>
> Bien sûr, et en tant que consultant, j'ai parfois vu de l'Ada absolument
>
> horrible (écrit par des gens qui n'avaient manifestement pas eu de
>
> formation adéquate).
>
>
>
> La question est plutôt de savoir si on peut écrire des choses propres
>
> dans les différents langages. Et ce qui me gène avec C (et encore plus
>
> avec C++ qui devrait s'en affranchir), c'est qu'il est impossible
>
> d'oublier la représentation concrète des éléments et d'avoir une vue
>
> réellement abstraite. Ex: on ne peut ignorer qu'un chaîne de caractères
>
> n'est qu'un pointeur sur le premier élément!
>
>
>
> --
>
> J-P. Rosen
>
> Adalog
>
> 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
>
> Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
>
> http://www.adalog.fr

Bonjour Monsieur ROSEN,

Nous sommes en grande partie d'accord.

Chaque langage a ses qualités et ses défauts, même le C++.

Le C en bas niveau, Ada tant qu'on peut, le C++ pour les GUI parce que WxWidgets et gtkmm !

C'est toujours la même question du choix des outils et des méthodes.
Il y en a qui veulent tout traiter à coup de marteau / burin...

slos

unread,
Mar 28, 2013, 6:50:24 PM3/28/13
to
Le vendredi 22 mars 2013 15:56:53 UTC+1, gautier...@hotmail.com a écrit :
Bonjour,

Dans :
http://en.wikibooks.org/wiki/Ada_Programming/Type_System

il y a un chapitre sur les Overlays qui mentionne donc votre technique.

Juste en dessous, on trouve :
Export / Import

Just for the record: There is still another method using the Export and Import pragmas. However, since this method completely undermines Ada's visibility and type concepts even more than overlays, it has no place here in this language introduction and is left to experts.

Quelque expert pourrait-il fournir une explication ?

Merci d'avance.

Stéphane

Ludovic Brenta

unread,
Mar 29, 2013, 1:57:44 PM3/29/13
to
slos writes on fr.comp.lang.ada:
> Just for the record: There is still another method using the Export
> and Import pragmas. However, since this method completely undermines
> Ada's visibility and type concepts even more than overlays, it has no
> place here in this language introduction and is left to experts.
>
> Quelque expert pourrait-il fournir une explication ?

On peut déclarer une variable de type T1 et l'exporter avec un nom
externe "foo".

Ensuite on peut déclarer une seconde variable de type T2 et l'importer
depuis le même nom externe "foo".

Si c'est réservé aux experts c'est pour de bonnes raisons... par
exemple, il faut tenir compte de la durée de vie de la variable, de sa
taille, etc. Cette technique est *déconseillée*.

--
Ludovic Brenta.

slos

unread,
Mar 29, 2013, 3:49:43 PM3/29/13
to
Merci Monsieur !

Donc je peux faire quelque chose du style ?

type Generic_Msg is
record
Header : Header_Type;
Data : Byte_Array (0..Max);
end record;
pragma Export(Ada, Generic_Msg);

type Cmd1_Msg is
record
Header : Header_Type;
Cmd1_Data : Cmd1_Type;
end record;
pragma Import(Ada, Cmd1_Msg, "Generic_Msg");

Je m'avoue perplexe.

Je pense qu'il vaut mieux que je confine cette gestion dans des fonctions en C... pour le moment du moins.

Cordialement,
Stéphane

Bonnes fêtes de Pâques !


Ludovic Brenta

unread,
Mar 29, 2013, 4:36:02 PM3/29/13
to
slos writes:
> Donc je peux faire quelque chose du style ?
>
> type Generic_Msg is
> record
> Header : Header_Type;
> Data : Byte_Array (0..Max);
> end record;
> pragma Export(Ada, Generic_Msg);
>
> type Cmd1_Msg is
> record
> Header : Header_Type;
> Cmd1_Data : Cmd1_Type;
> end record;
> pragma Import(Ada, Cmd1_Msg, "Generic_Msg");

Non.

> Je m'avoue perplexe.

Parce que vous n'êtes pas un expert :)

> Je pense qu'il vaut mieux que je confine cette gestion dans des
> fonctions en C... pour le moment du moins.

Ce n'est pas une question de langage. Il s'agit de comprendre ce que
fait le code objet émis par le compilateur. Vous pouvez (et devriez)
écrire le plus possible en Ada pour obtenir le code objet désiré.

--
Ludovic Brenta.

J-P. Rosen

unread,
Mar 29, 2013, 5:34:16 PM3/29/13
to
Le 29/03/2013 18:57, Ludovic Brenta a écrit :
> Si c'est réservé aux experts c'est pour de bonnes raisons... par
> exemple, il faut tenir compte de la durée de vie de la variable, de sa
> taille, etc. Cette technique est *déconseillée*.
Et des alignements qui peuvent être incompatibles!

J-P. Rosen

unread,
Mar 29, 2013, 5:39:25 PM3/29/13
to
Le 29/03/2013 20:49, slos a �crit :
> Donc je peux faire quelque chose du style ?
[Horreur censur�e, pas la peine de les r�pandre...]

Il y a quelques moyens tordus connus des experts pour court-circuiter
les contr�les... Mais ils laissent quand m�me des traces rep�rables par
les outils (AdaControl par exemple).

slos

unread,
Mar 30, 2013, 5:26:34 PM3/30/13
to
Je m'attendais un peu à votre réponse.
Je ne suis pas un expert en Ada, juste un apprenant.

J'ai peut-être commencé par un côté un peu abrupt, c'est dans ma nature...
A mon âge, on change difficilement.

Il faut dire que les concepts standards du langage ne me posent que peu de problèmes, j'ai de bons livres, et l'on trouve de l'information de qualité sur le web. On a même de bons avis ici !

Cependant, les applications qui m'intéressent font appel à des strates logicielles qui sont écrites en C, et je ne connais pas de bindings Ada déjà tout prêts. Aussi, et malgré mon ignorance crasse, je l'admet, je tente de pallier à cet état de fait, qui plus est sous licence GMGPL.

Je suis persuadé de l'intérêt de Ada, avec quelques bémols, et je voudrais bien l'utiliser autant que possible. Cependant, les difficultés que je rencontre comme celle exprimée dans ce fil de discussion sont aujourd'hui pour moi sans solution, sauf l'évidente, traiter ces messages en C.

En plus, ça ne me pose pas de problème, ni technique, ni philosophique.
Je suis un pragmatique idéaliste...

Cordialement,
Stéphane

slos

unread,
Mar 30, 2013, 5:28:07 PM3/30/13
to
Of course, mais ce n'est pas propre à Ada.
Je suis confronté très régulièrement à cet écueil.

slos

unread,
Mar 30, 2013, 5:45:32 PM3/30/13
to
Le vendredi 29 mars 2013 22:39:25 UTC+1, J-P. Rosen a écrit :
> Le 29/03/2013 20:49, slos a écrit :
>
> > Donc je peux faire quelque chose du style ?
>
> [Horreur censurée, pas la peine de les répandre...]
>
>
>
> Il y a quelques moyens tordus connus des experts pour court-circuiter
>
> les contrôles... Mais ils laissent quand même des traces repérables par
>
> les outils (AdaControl par exemple).
>
>
>
> --
>
> J-P. Rosen
>
> Adalog
>
> 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
>
> Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
>
> http://www.adalog.fr

Je ne souhaite court-circuiter les contrôles que si c'est l'unique solution.

Dans la communication, les messages traversent de multiples couches.

Lors de la traversée, on s'occupe de router ou de reconstituer un message et pas à son contenu.

Le message traverse les différentes couches le plus souvent sans recopie, seul le pointeur du message est transféré dans les queues des tâches implémentant les couches. Évidemment, cela ne s'applique pas aux frontières du système.

Je pense que je ne vous apprends rien. J'essaie juste d'illustrer mon propos.

Donc, je souhaite utiliser Ada pour l'application qui traite les messages en bout et qui s'intéresse au contenu de ces messages.

Une tâche pour gérer l'interface avec les boites aux lettres doit donc router le message à d'autres tâches gérant par exemple les indications de diagnostic, les réponses à des requêtes, toutes sortes...

Les tâches peuvent ainsi recevoir un message générique et ce message doit pouvoir être interprété selon son contenu, si possible sans recopie, car une trame Ethernet, c'est 1500 octets.

En C, c'est élémentaire.

En Ada, je ne sais toujours pas faire.

Cela me désole, croyez le bien.

Cordialement,
Stéphane

Ludovic Brenta

unread,
Apr 2, 2013, 9:42:26 AM4/2/13
to
slos a écrit sur fr.comp.lang.ada:
> Je m'attendais un peu à votre réponse.
>
> Je ne suis pas un expert en Ada, juste un apprenant.
>
> J'ai peut-être commencé par un côté un peu abrupt, c'est dans ma
> nature... A mon âge, on change difficilement.

Pas grave, moi aussi je suis parfois abrupt :)

> Il faut dire que les concepts standards du langage ne me posent que
> peu de problèmes, j'ai de bons livres, et l'on trouve de l'information
> de qualité sur le web. On a même de bons avis ici !
>
> Cependant, les applications qui m'intéressent font appel à des strates
> logicielles qui sont écrites en C, et je ne connais pas de bindings Ada
> déjà tout prêts. Aussi, et malgré mon ignorance crasse, je l'admet, je
> tente de pallier à cet état de fait, qui plus est sous licence GMGPL.

En relisant ce fil de discussion je ne réalise que maintenant que
personne n'a répondu à la question initiale qui était en substance:
en C on convertit des pointeurs vers X en des pointeurs vers Y, ça
marche très bien, est-ce que Unchecked_Conversion en Ada peut faire la
même chose?

La réponse est, bien entendu, oui. Mais attention à bien convertir les
pointeurs (ou valeurs accès en Ada) et non pas les objets pointés.
Ensuite, si Unchecked_Conversion conduit à des recopies, ce n'est pas
grave puisque l'on ne recopie jamais que des pointeurs.

Exemple (non compilé et non essayé, caveat emptor):

type Tag_T is (Message_Type_1, ...., Message_Type_N);

type Header_T is record
Length : Natural;
Tag : Tag_T;
end record;
for Header_T use record
Length at 0 range 0 .. 31;
Tag at 4 range 0 .. 31;
end record;
type Header_Access_T is access all Header_T;

function Next return Header_Access_T;

type Measures_Array_T is array (Positive range <>) of Integer;
type Message_1_T (Array_Length : Natural) is record
Header : Header_T; -- where Header.Tag = Message_Type_1
Measures : Measures_Array_T (1 .. Array_Length);
end record;
for Message_1_T use record
Header at 0 range 0 .. 63;
Array_Length at 8 range 0 .. 31;
end record;
type Message_1_Access_T is access all Message_1_T;

procedure Process (Message_1 : in Message_1_T);

function To_Message_1 is
new Ada.Unchecked_Conversion (Source => Header_Access_T,
Target => Message_1_Access_T);


loop
declare
Next_Message : constant Header_Access_T := Next;
begin
case Next_Message.Tag is
...
when Message_Type_1 =>
Process (Message_1 => To_Message_1 (Next_Message).all);
end case;
end;
end loop;

--
Ludovic Brenta.

Georg Bauhaus

unread,
Apr 3, 2013, 4:19:06 AM4/3/13
to
On 02.04.13 15:42, Ludovic Brenta wrote:
> La r�ponse est, bien entendu, oui. Mais attention � bien convertir les
> pointeurs (ou valeurs acc�s en Ada) et non pas les objets point�s.
> Ensuite, si Unchecked_Conversion conduit � des recopies, ce n'est pas
> grave puisque l'on ne recopie jamais que des pointeurs.

Une possibilit�e suppl�mentaire : si en C, c'est �l�mentaire, en Ada,
il fault seulement le dire.

package View_Cmd1 is new
System.Address_To_Access_Conversions (Cmd1_Msg);
package View_Generic is new
System.Address_To_Access_Conversions (Generic_Msg);

En plus de ces conversions, B.3 garantit que on ne recopie pas des objects
correspondants aux structs en C. (Je pense que une variante de Streams.Read
aide aussi, si ce variante ne consomme pas.)

http://www.adapower.com/index.php?Command=Class&ClassID=Advanced&CID=213



with Interfaces.C;

package Ada_Side is

pragma Elaborate_Body (Ada_Side);

subtype Byte_Type is Interfaces.C.unsigned_char;
-- cf. System.Storage_Element, System.Storage_Unit

type Header_Num is range 0..1;
type Header_Type is array (Header_Num) of Byte_Type;
type Byte_Array is array (Natural range <>) of aliased Byte_Type;

Max : constant := 7;

-- 1.

type Generic_Msg is
record
Header : Header_Type;
Data : Byte_Array (0..Max);
end record;
pragma Convention (C, Generic_Msg);

procedure Pass_Generic_Msg (X : Generic_Msg);
pragma Export (C, Pass_Generic_Msg, "ada_side__pass_generic_msg");


-- 2.

type Cmd1_Type is record
Upper : String (1..Max/2+1);
Lower : String (Max/2+1+1..Max+1);
end record;

type Cmd1_Msg is
record
Header : Header_Type;
Cmd1_Data : Cmd1_Type;
end record;

procedure Pass_Cmd1_Msg (X : Cmd1_Msg);
pragma Export (C, Pass_Cmd1_Msg, "ada_side__pass_cmd1_msg");


-- 3.

function Call_Me return Interfaces.C.int;
pragma Import (C, Call_Me, "c_side__call_me");

procedure Receive_Generic_Msg (X : out Generic_Msg);
pragma Export (C, Receive_Generic_Msg, "ada_side__receive_generic_msg");

procedure Receive_Cmd1_Msg (X : out Cmd1_Msg);
pragma Export (C, Receive_Cmd1_Msg, "ada_side__receive_cmd1_msg");


-- 4.

procedure Process_Generic (X : in out Generic_Msg);

procedure If_Header_Says (X : in out Cmd1_Msg);

type Msg_Pointer is access all Generic_Msg;
function As_Generic_Msg (X : Cmd1_Msg) return Msg_Pointer;

end Ada_Side;

-- 8< --

#define MAX 8

typedef unsigned char byte;

enum hdr { zero, un, deux, trois };
struct generic_msg {
byte header[2];
byte bytes[MAX];
};

/* Ici, il n'y a pas une d�finition de struct cmd1_msg ! */

extern void ada_side__pass_generic_msg(void*);
extern void ada_side__pass_cmd1_msg(void*);
extern void ada_side__receive_generic_msg(struct generic_msg*);
extern void ada_side__receive_cmd1_msg(void*);

int c_side__call_me(void)
{
struct generic_msg msg;
int k;

msg.header[0] = (byte)un, msg.header[1] = (byte)deux;

for (k=0; k<MAX; ++k)
msg.bytes[k] = 'A'+k;

ada_side__pass_generic_msg(&msg);
ada_side__receive_generic_msg(&msg);

ada_side__pass_cmd1_msg(&msg);
ada_side__receive_cmd1_msg(&msg);

ada_side__pass_cmd1_msg(&msg);
ada_side__receive_generic_msg(&msg);

ada_side__pass_generic_msg(&msg);
ada_side__receive_cmd1_msg(&msg);

return 0;
}

-- >8 --

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Characters.Handling;
with System.Address_To_Access_Conversions;

package body Ada_Side is

package Byte_IO is new Modular_IO (Byte_Type);

package View_Cmd1 is new
System.Address_To_Access_Conversions (Cmd1_Msg);
package View_Generic is new
System.Address_To_Access_Conversions (Generic_Msg);

The_Pointer : View_Generic.Object_Pointer;

procedure Show_Header (H : Header_Type);

function As_Generic_Msg (X : Cmd1_Msg) return Msg_Pointer is
Result : View_Generic.Object_Pointer;
begin
Result := View_Generic.To_Pointer (X'Address);
return Msg_Pointer (Result);
end As_Generic_Msg;

procedure If_Header_Says (X : in out Cmd1_Msg) is
begin
Put_Line ("processing a CMD 1");
end If_Header_Says;

procedure Pass_Cmd1_Msg (X : Cmd1_Msg) is
Data : Cmd1_Type renames X.Cmd1_Data;

use Interfaces.C;
begin
-- save:
The_Pointer := View_Generic.To_Pointer (X'Address);

Show_Header (X.Header);

Put_Line ("* CMD1:");

Put ("part U:");
Put (Data.Upper);
New_Line;

Put ("part L:");
Put (Data.Lower);
New_Line;
end Pass_Cmd1_Msg;

procedure Pass_Generic_Msg (X : Generic_Msg) is
begin
-- save:
The_Pointer := View_Generic.To_Pointer (X'Address);

Show_Header (X.Header);

-- dump:
Put_Line ("@ MSG:");
for K in X.Data'Range loop
Byte_IO.Put (X.Data (K));
end loop;
New_Line;
end Pass_Generic_Msg;

procedure Process_Generic (X : in out Generic_Msg) is
-- si on ne veut pas le Unchecked_Conversion et pas
-- les d�finitions comme for X'Address use ...
It : View_Cmd1.Object_Pointer := View_Cmd1.To_Pointer (X'Address);
begin
case X.Header (X.Header'First) is
when 1 =>
If_Header_Says (It.all);
when others =>
null;
end case;
end Process_Generic;

procedure Receive_Cmd1_Msg (X : out Cmd1_Msg) is
-- LRM B.3 (69/2)
use Ada.Characters.Handling, Interfaces.C;
procedure Toggle_Case (Pfx : in out Character) is
begin
if Pfx in 'A' .. 'Z' then
Pfx := To_Lower (Pfx);
else
Pfx := To_Upper (Pfx);
end if;
end Toggle_Case;
Data : Cmd1_Type renames X.Cmd1_Data;
begin
X := View_Cmd1.To_Pointer (The_Pointer.all'Address).all;

Toggle_Case (Data.Upper (Data.Upper'First));
Toggle_Case (Data.Lower (Data.Lower'First));
end Receive_Cmd1_Msg;

procedure Receive_Generic_Msg (X : out Generic_Msg) is
-- LRM B.3 (69/2)
begin
X := The_Pointer.all;
end Receive_Generic_Msg;

procedure Show_Header (H : Header_Type) is
package HNum_IO is new Integer_IO (Header_Num);
begin
HNum_IO.Default_Width := 1;
Put_Line (">");
for K in H'Range loop
Put ('H'); HNum_IO.Put (K); Put (':');
Byte_IO.Put (H (K)); New_Line;
end loop;
end Show_Header;

begin
Byte_IO.Default_Base := 16;
Byte_IO.Default_Width := 8;
end Ada_Side;

with Ada_Side; use Ada_Side;
with Interfaces.C;

procedure Test_Ada_Side is
Result : Interfaces.C.int;
Stuff : Cmd1_Msg;
begin
Result := Call_Me; -- calling C, which in turn calls Ada

Stuff.Header (0) := 0;
Process_Generic (As_Generic_Msg (Stuff).all);
Stuff.Header (0) := 1;
Process_Generic (As_Generic_Msg (Stuff).all);
end Test_Ada_Side;


$ ./test_ada_side
>
H0: 16#1#
H1: 16#2#
@ MSG:
16#41# 16#42# 16#43# 16#44# 16#45# 16#46# 16#47# 16#48#
>
H0: 16#1#
H1: 16#2#
* CMD1:
part U:ABCD
part L:EFGH
>
H0: 16#1#
H1: 16#2#
* CMD1:
part U:aBCD
part L:eFGH
>
H0: 16#1#
H1: 16#2#
@ MSG:
16#61# 16#42# 16#43# 16#44# 16#65# 16#46# 16#47# 16#48#
processing a CMD 1


slos

unread,
Apr 3, 2013, 4:45:00 PM4/3/13
to
Merci Monsieur Brenta.

Je m'en vais éplucher cela...

Il reste qu'il est nécessaire de créer des structures Ada à l'image de celles en C. Et cela fait beaucoup de structures dans mon cas.
J'ai essayé la conversion automatique mais je suis moyennement satisfait du résultat. C'est pourquoi pour le binding de libmodbus j'ai procédé à la mano.

Je ne sais pas s'il y a des "best practices" pour réaliser proprement ce genre de choses.

Cordialement,
Stéphane

slos

unread,
Apr 3, 2013, 4:53:28 PM4/3/13
to
Le mercredi 3 avril 2013 10:19:06 UTC+2, Georg Bauhaus a écrit :
> On 02.04.13 15:42, Ludovic Brenta wrote:
>
> > La réponse est, bien entendu, oui. Mais attention à bien convertir les
>
> > pointeurs (ou valeurs accès en Ada) et non pas les objets pointés.
>
> > Ensuite, si Unchecked_Conversion conduit à des recopies, ce n'est pas
>
> > grave puisque l'on ne recopie jamais que des pointeurs.
>
>
>
> Une possibilitée supplémentaire : si en C, c'est élémentaire, en Ada,
> /* Ici, il n'y a pas une définition de struct cmd1_msg ! */
> -- les définitions comme for X'Address use ...
Merci Monsieur Bauhaus pour cette réponse qui a dû vous demander un peu de votre précieux temps.

Je suis certain d'y trouver de nombreuses et pertinentes informations et je m'y pencherai très bientôt.

Cordialement,
Stéphane

PS : complètement hors sujet, Bauhaus était le nom d'un de mes groupes préférés dans mon jeune temps...

0 new messages