我声明了一个这样的联合类型:
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)。
答案 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;