1

我声明一个这样的联合类型:

type Access_Kind is (Named, Indexed);
type Array_Type is array (0 .. 1) of Integer;

type Record_Type (Kind : Access_Kind := Access_Kind'First) is record
   case Kind is
      when Named =>
         X, Y : Integer;
      when Indexed =>
         S : Array_Type;
   end case;
end record;
pragma Unchecked_Union (Record_Type);
pragma Convention (C_Pass_By_Copy, Record_Type);

function Create (X, Y : Integer) return Record_Type;

现在,当我尝试创建派生类型时:

type Integer2 is new Record_Type;

GNAT 给了我以下警告:

warning: in instantiation at line [pragma Convention...]
warning: variant record has no direct equivalent in C
warning: use of convention for type "Integer2" is dubious

所以看起来 pragma 约定适用于派生类型,但 Unchecked_Union 不是。我无法再次将其应用于派生类型,因为Record_Type已经定义了原始操作(Integer2在另一个包中定义)。

这是正确的行为还是 GNAT 错误?如何正确地从 Unchecked_Union 类型派生,以便新类型继承 Unchecked_Union pragma?

GNAT 版本:GNAT GPL 2012 (20120509)。

4

2 回答 2

4

一种可能性是Record_Type在嵌套包中声明 的操作,例如Ops,这样它们就不是原始的:

package Union is

   type Access_Kind is (Named, Indexed);
   type Array_Type is array (0 .. 1) of Integer;

   type Record_Type (Kind : Access_Kind := Access_Kind'First) is record
      case Kind is
         when Named =>
            X, Y : Integer;
         when Indexed =>
            S : Array_Type;
      end case;
   end record;
   pragma Unchecked_Union (Record_Type);
   pragma Convention (C_Pass_By_Copy, Record_Type);

   --  If P was declared immediately within Union, it would be
   --  primitive, and it wouldn't be possible to declare
   --  representation aspects for Integer2.
   package Ops is
      procedure P (R : Record_Type) is null;
      --  "is null" only so that I can use -gnatR without needing a
      --  body.
   end Ops;

   type Integer2 is new Record_Type;
   pragma Unchecked_Union (Integer2);
   pragma Convention (C_Pass_By_Copy, Integer2);

end Union;

使用-gnatR显示选择的表示,我得到

$ gnatmake -c -u -f -gnatwa union.ads -gnatR
gcc -c -gnatwa -gnatR -gnat05 union.ads

Representation information for unit Union (spec)
------------------------------------------------

for Array_Type'Size use 64;
for Array_Type'Alignment use 4;
for Array_Type'Component_Size use 32;

for Record_Type'Size use 64;
for Record_Type'Alignment use 4;
for Record_Type use record
   Kind at ?? range  0 ..  -1;
   X    at  0 range  0 .. 31;
   Y    at  4 range  0 .. 31;
   S    at  0 range  0 .. 63;
end record;

for Integer2'Size use 64;
for Integer2'Alignment use 4;
for Integer2 use record
   Kind at ?? range  0 ..  -1;
   X    at  0 range  0 .. 31;
   Y    at  4 range  0 .. 31;
   S    at  0 range  0 .. 63;
end record;

也就是说,我认为 GNAT 的行为是错误的。

ARM 13.1(0.1)表示存在表示操作方面,并且(1)定义了表示方面。(10)这就是为什么我们需要避免原始操作。(15)表示表示方面由派生类型继承;但是(15.1)表示操作方面不是,“除非指定”特定方面。我猜“指定”的意思是“在 ARM 中用于语言定义的方面,或者由供应商用于供应商定义的方面”。

B3.3(3.1)声明这Unchecked_Union是一个表示方面。因此,它应该被继承。

B3.1(0.1)声明接口方面,包括Convention,是表示方面。C_Pass_By_Copy所以应该继承。

我会写一个错误报告。

于 2013-02-03T10:34:24.507 回答
1

在 Ada 2012 中,pragma Unchecked_Union已过时,您现在可以指定 aspect Unchecked_Union。在这两种情况下,正如Ada 2005 的基本原理:6.4 Pragmas and Restrictions中所讨论的,该警告提醒人们,未经检查的联合类型“在 Ada 2005 中引入的唯一目的是与 C 程序接口,而不是为了危险地生活。” 派生的类型Record_Type不被禁止;这只是一个坏主意,因为它会传播错误执行的机会,如注释部分所示。相反,将联合封装在绑定的主体中并从更高级别的类型派生。

附录:检查旧版本以供参考,

GNAT 4.6
版权所有 1996-2010,自由软件基金会,Inc。
...
未选中的单元的表示信息(主体)
-------------------------------------------------- --

对于 Array_Type'Size 使用 64;
对于 Array_Type'Alignment 使用 4;
对于 Array_Type'Component_Size 使用 32;

对于 Record_Type'Size 使用 64;
对于 Record_Type'Alignment 使用 4;
对于 Record_Type 使用记录
   亲切?? 范围 0 .. -1;
   X 在 0 范围 0 .. 31;
   Y 在 4 范围 0 .. 31;
   S 在 0 范围内 0 .. 63;
结束记录;

对于 Integer2'Size 使用 96;
对于 Integer2'Alignment 使用 4;
对于 Integer2 使用记录
   种类在 0 范围 0 .. 7;
   X 在 4 范围 0 .. 31;
   Y 在 8 范围 0 .. 31;
   S 在 4 范围内 0 .. 63;
结束记录;
于 2013-02-02T16:19:19.250 回答