2016-10-17 4 views
3

Je rencontre un problème d'interfaçage avec C d'ada. En particulier, j'ai cette déclaration ada:Ada envoyant un tampon d'octets à c

type Byte is mod 256; pragma Convention (C, Byte); 
type ByteStream is array (Interfaces.C.size_t range <>) of Byte; 
    pragma Convention (C, ByteStream); 
type VoidPointer is access all ByteStream; 
type ByteBuffer is 
    record 
     data : VoidPointer; 
     size : Interfaces.C.size_t; 
    end record; 
pragma Convention (C, ByteBuffer); 
procedure Free is new Ada.Unchecked_Deallocation (ByteStream, VoidPointer); 

et cette déclaration C:

struct ByteBuffer { 
    unsigned char *data; 
    size_t size; 
}; 

et cette importation ada:

function My_Function (
    data : in ByteBuffer) 
    return Interfaces.C.int; 
pragma Import (C, My_Function, "my_function"); 

et cette déclaration C:

int my_function(struct ByteBuffer data); 

Et pourtant, quand je débogue mon code Je trouve une taille de (dans un exemple) 110 sur le côté ada, mais 0x7fffffffe750 sur le côté c. Pourquoi ma taille n'est-elle pas mutilée? (Remarque: les données elles-mêmes sont également tronquées, mais nous espérons que la réparation corrigera l'autre).

+0

Probablement le rembourrage de la structure C. Je ne sais pas comment Ada gère ses dossiers. Ou quelques bugs dans votre code. –

+0

J'aurais pensé que 'Convention pragma (C, ByteBuffer);' aurait résolu cela. Peut-être que je dois aussi spécifier quelque chose du côté C? – LambdaBeta

+0

Le remplissage est spécifique au compilateur. Il n'y a pas de "convention C" à ce sujet. –

Répondre

3

Le paramètre in dans Ada peut utiliser une référence ou une copie, mais sa taille dépend du compilateur/de la structure.

Pour forcer les deux parties à utiliser des pointeurs (la meilleure chose à faire ici), vous pouvez le faire:

Du côté Ada:

function My_Function (
    data : access ByteBuffer) 
    return Interfaces.C.int; 
pragma Import (C, My_Function, "my_function"); 

Et du côté C:

int my_function(const struct ByteBuffer *data); 

Puisque ByteBuffer est un tableau contraint, une autre information transmet: les limites qui est un pointeur (le pointeur entier est un pointeur "gras"). Vous pouvez « sauter » sur le côté C en faisant ceci:

struct ByteBuffer { 
    unsigned char *data; 
    void *skipit; // ignore this value 
    size_t size; 
}; 

Pour forcer Ada passer par copie, vous pouvez utiliser pragma Convention(C_Pass_By_Copy,ByteBuffer) après la déclaration de type (côté Ada)

+0

Je viens d'essayer ça. Maintenant, les données à l'intérieur du bytebuffer sont correctes (YAY!) Mais size_t est toujours mutilé. :(On dirait que la structure peut en effet être rembourrée comme l'a dit Eugène, il se peut que je doive diviser le tampon et sa taille manuellement, – LambdaBeta

+0

cela peut s'expliquer Voir mon edit –

+0

Merveilleux, c'était effectivement le problème. si skipit stocke les limites, y a-t-il un moyen d'accéder directement à celles-ci sur le côté C. – LambdaBeta

0

Ada de chaînes non limitées a un compilateur cartographie de données dépendantes. Dans celui que j'utilise, j'ai vérifié qu'il commence par quelque chose (comme une balise) qui dit à propos de la taille de la chaîne, puis vient le tableau "normal" d'octets. Lorsque vous passez le tampon de C à Ada, ce dernier va prendre la longueur du tableau non borné des premiers éléments de votre tableau C. Je ne sais pas pourquoi vous avez besoin de votre exemple, mais si je suppose que vous allez pointer des tableaux de données déjà créées, vous pouvez déclarer ByteStream comme un tableau fixe (disons aussi grand que votre taille maximale) parce que vous allez gérer la taille réelle avec votre paramètre "taille". En d'autres termes, cela n'a aucun sens que vous ayez dans ada le paramètre "size" de votre enregistrement ByteBuffer car il va dans la structure de chaîne pointée sans limite et peut être extrait avec l'attribut 'Length'.