Ada-C绑定应用程序中映射结构成员的最佳实践

Ada-C绑定应用程序中映射结构成员的最佳实践,c,struct,ada,C,Struct,Ada,在需要在C和Ada中定义的函数之间传递和读/写结构(记录)的Ada-C绑定应用程序中,在C和Ada端声明结构器以确保两种语言之间成员的正确映射的最佳方法是什么。例如,我在C中声明了一个结构(这里不使用位字段),但在Ada端,在声明相同结构(Ada中的记录)的同时,我还使用userepresentation子句将其按位映射,然后使用约定C pragma。我看到的是Ada没有正确读取结构,这可能是因为成员的位映射错误 我只是想知道在Ada和C端确保相同结构的正确声明的最佳方法是什么。是否应在C端使用

在需要在C和Ada中定义的函数之间传递和读/写结构(记录)的Ada-C绑定应用程序中,在C和Ada端声明结构器以确保两种语言之间成员的正确映射的最佳方法是什么。例如,我在C中声明了一个结构(这里不使用位字段),但在Ada端,在声明相同结构(Ada中的记录)的同时,我还使用userepresentation子句将其按位映射,然后使用约定C pragma。我看到的是Ada没有正确读取结构,这可能是因为成员的位映射错误

我只是想知道在Ada和C端确保相同结构的正确声明的最佳方法是什么。是否应在C端使用位字段声明结构,然后使用相同的位方案在Ada端使用使用表示子句标记相同的结构/记录

例如在C中

/* Position Data Structure */
typedef struct {
    float lat;
    float lon;
} POSITION_TYPE;

/* Fix Data Structure */
typedef struct {
    int32_t fix_id;
    char fix_type[20];
    char leg_type[7];
    char ident[8];
    char ident_code[11];
    char fix_descriptor[30];
    char way_ident[7];
    char ref_pt[8];
    char ref_pt_code[11];
    POSITION_TYPE position;
} FIX_DATA_TYPE;
我在Ada中声明了与以下相同的结构:

  -- Position Record --------------------------------------------------------
  type Pos_Rec_Type is
    record
      Lat : C.C_float;
      Lon : C.C_float;
    end record;

    for Pos_Rec_Type use
      record
        Lat at 0 range  0..31;
        Lon at 0 range 32..63;
      end record;

   pragma Convention (Convention => C, Entity => Pos_Rec_Type);

  -- Fix Data Record --------------------------------------------------------
  type Fix_Data_Rec_Type is
    record
      Fix_Id              : C.int;
      Fix_Type            : C.char_array(1..20);
      Leg_Type            : C.char_array(1..7);
      Ident               : C.char_array(1..8);
      Ident_Code          : C.char_array(1..11);
      Fix_Desc            : C.char_array(1..30);
      Way_Ident           : C.char_array(1..7);
      Ref_Pt              : C.char_array(1..8);
      Ref_Pt_Code         : C.char_array(1..11);
      Position            : Pos_Rec_Type;
   end record;

    for Fix_Data_Rec_Type use
      record
        Fix_Id              at 0 range   0..31;
        Fix_Type            at 0 range  32..191;
        Leg_Type            at 0 range 192..247;
        Ident               at 0 range 248..311;
        Ident_Code          at 0 range 312..399;
        Fix_Desc            at 0 range 400..639;
        Way_Ident           at 0 range 640..695;
        Ref_Pt              at 0 range 696..759;
        Ref_Pt_Code         at 0 range 760..847;
        Position            at 0 range 848..911;
      end record;

   pragma Convention (Convention => C, Entity => Fix_Data_Rec_Type);

但当我在Ada端填充这个结构并将其转换为C函数时,我发现位置记录没有正确解码。当我为Fix\u Data\u Rec\u Type禁用representation子句时,它工作正常。

如果使用
-gnatR
打印类型的表示信息,您会发现

附rep条款:

for Pos_Rec_Type'Size use 64;
for Pos_Rec_Type'Alignment use 4;
for Pos_Rec_Type use record
   Lat at 0 range  0 .. 31;
   Lon at 4 range  0 .. 31;
end record;

for Fix_Data_Rec_Type'Object_Size use 928;
for Fix_Data_Rec_Type'Value_Size use 912;
for Fix_Data_Rec_Type'Alignment use 4;
for Fix_Data_Rec_Type use record
   Fix_Id      at   0 range  0 .. 31;
   Fix_Type    at   4 range  0 .. 159;
   Leg_Type    at  24 range  0 .. 55;
   Ident       at  31 range  0 .. 63;
   Ident_Code  at  39 range  0 .. 87;
   Fix_Desc    at  50 range  0 .. 239;
   Way_Ident   at  80 range  0 .. 55;
   Ref_Pt      at  87 range  0 .. 63;
   Ref_Pt_Code at  95 range  0 .. 87;
   Position    at 106 range  0 .. 63;
end record;
for Pos_Rec_Type'Size use 64;
for Pos_Rec_Type'Alignment use 4;
for Pos_Rec_Type use record
   Lat at 0 range  0 .. 31;
   Lon at 4 range  0 .. 31;
end record;

for Fix_Data_Rec_Type'Size use 928;
for Fix_Data_Rec_Type'Alignment use 4;
for Fix_Data_Rec_Type use record
   Fix_Id      at   0 range  0 .. 31;
   Fix_Type    at   4 range  0 .. 159;
   Leg_Type    at  24 range  0 .. 55;
   Ident       at  31 range  0 .. 63;
   Ident_Code  at  39 range  0 .. 87;
   Fix_Desc    at  50 range  0 .. 239;
   Way_Ident   at  80 range  0 .. 55;
   Ref_Pt      at  87 range  0 .. 63;
   Ref_Pt_Code at  95 range  0 .. 87;
   Position    at 108 range  0 .. 63;
end record;
无代表条款:

for Pos_Rec_Type'Size use 64;
for Pos_Rec_Type'Alignment use 4;
for Pos_Rec_Type use record
   Lat at 0 range  0 .. 31;
   Lon at 4 range  0 .. 31;
end record;

for Fix_Data_Rec_Type'Object_Size use 928;
for Fix_Data_Rec_Type'Value_Size use 912;
for Fix_Data_Rec_Type'Alignment use 4;
for Fix_Data_Rec_Type use record
   Fix_Id      at   0 range  0 .. 31;
   Fix_Type    at   4 range  0 .. 159;
   Leg_Type    at  24 range  0 .. 55;
   Ident       at  31 range  0 .. 63;
   Ident_Code  at  39 range  0 .. 87;
   Fix_Desc    at  50 range  0 .. 239;
   Way_Ident   at  80 range  0 .. 55;
   Ref_Pt      at  87 range  0 .. 63;
   Ref_Pt_Code at  95 range  0 .. 87;
   Position    at 106 range  0 .. 63;
end record;
for Pos_Rec_Type'Size use 64;
for Pos_Rec_Type'Alignment use 4;
for Pos_Rec_Type use record
   Lat at 0 range  0 .. 31;
   Lon at 4 range  0 .. 31;
end record;

for Fix_Data_Rec_Type'Size use 928;
for Fix_Data_Rec_Type'Alignment use 4;
for Fix_Data_Rec_Type use record
   Fix_Id      at   0 range  0 .. 31;
   Fix_Type    at   4 range  0 .. 159;
   Leg_Type    at  24 range  0 .. 55;
   Ident       at  31 range  0 .. 63;
   Ident_Code  at  39 range  0 .. 87;
   Fix_Desc    at  50 range  0 .. 239;
   Way_Ident   at  80 range  0 .. 55;
   Ref_Pt      at  87 range  0 .. 63;
   Ref_Pt_Code at  95 range  0 .. 87;
   Position    at 108 range  0 .. 63;
end record;

使用rep子句时,
位置
组件实际上没有对齐(106不能被4整除)。

IIRC在表示子句中使用约定C可能会导致奇怪的行为-摆脱约定C[如果使用rep子句,无论如何都不需要约定C]。老实说,我编写了许多C绑定,而且几乎从未将约定C用于记录。注意字段类型。@Darkstkhan,如果我只在Ada端使用表示子句,我是否需要在C端使用位字段来声明结构?@Darkstkhan,那么,使用pragma C约定的应用程序是什么?为什么在这里使用它不是一个好主意?添加MCVE可能会鼓励更好的答案。我认为您自己也回答了这个问题<代码>约定C单独起作用,允许编译器在两侧选择相同的代表(我将建议这样做)。添加Rep子句会覆盖这一点,迫使Ada编译器遵循您的选择——但这无法影响C编译器。因此,如果必须使用rep子句,那么您需要知道C编译器是如何工作的,或者需要在C端显式指定相同的对齐方式。(例如,当使用-m32或编译器的某些旧版本编译时,您可能会发现此rep子句与C选项匹配)-gnatR看起来很有用!