从Unchecked_Union派生

时间:2013-02-02 15:17:59

标签: ada gnat

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

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 Convention应用于派生类型,但Unchecked_Union不适用。我无法再将它应用于派生类型,因为Record_Type已经定义了基本操作(Integer2在另一个包中定义)。

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

GNAT版本:GNAT GPL 2012(20120509)。

2 个答案:

答案 0 :(得分: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应该被继承。

我会编写错误报告。

答案 1 :(得分:1)

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

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

GNAT 4.6
Copyright 1996-2010, Free Software Foundation, Inc.
...
Representation information for unit Unchecked (body)
----------------------------------------------------

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 96;
for Integer2'Alignment use 4;
for Integer2 use record
   Kind at 0 range  0 ..  7;
   X    at 4 range  0 .. 31;
   Y    at 8 range  0 .. 31;
   S    at 4 range  0 .. 63;
end record;