Ada 源于未检查的联合
我声明的联合类型如下:Ada 源于未检查的联合,ada,gnat,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 =
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约定应用于派生类型,但未选中的联合不是。我无法将其再次应用于派生类型,因为Record\u type
已经定义了基本操作(Integer2
在另一个包中定义)
这是正确的行为还是蚊虫?如何正确地从未检查的\u Union类型派生,以便新类型继承未检查的\u Union pragma
GNAT版本:GNAT GPL 2012(20120509)。在Ada 2012中已过时,您现在可以指定方面。在这两种情况下,如中所述,警告提醒人们,未经检查的联合类型“在Ada 2005中引入的唯一目的是与C程序接口,而不是危险地生活。”不禁止从记录类型派生的类型;这只是一个坏主意,因为它传播了错误执行的机会,如本节所示。相反,将联合封装在绑定体中,并从更高级别的类型派生
附录:检查旧版本以供参考
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;
蚊虫4.6
版权所有,1996年至2010年,自由软件基金会。
...
未选中单元的表示信息(主体)
----------------------------------------------------
对于数组_类型的大小,使用64;
对于数组_类型的对齐,使用4;
对于数组类型“组件大小”使用32;
对于记录类型“大小”使用64;
对于“校准”类型的记录,使用4;
对于记录类型,请使用记录
种类在??范围0-1.
0范围内的X。。31;
Y在4范围0。。31;
S在0范围0。。63;
结束记录;
对于整数2’大小,使用96;
对于整数2'对齐,使用4;
对于整数2,请使用记录
种类在0范围0。。7.
X在4范围内0。。31;
Y在8范围0。。31;
S在4范围0。。63;
结束记录;
在Ada 2012中,已过时,现在可以指定方面。在这两种情况下,如中所述,警告提醒人们,未经检查的联合类型“在Ada 2005中引入的唯一目的是与C程序接口,而不是危险地生活。”不禁止从记录类型派生的类型;这只是一个坏主意,因为它传播了错误执行的机会,如本节所示。相反,将联合封装在绑定体中,并从更高级别的类型派生
附录:检查旧版本以供参考
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;
蚊虫4.6
版权所有,1996年至2010年,自由软件基金会。
...
未选中单元的表示信息(主体)
----------------------------------------------------
对于数组_类型的大小,使用64;
对于数组_类型的对齐,使用4;
对于数组类型“组件大小”使用32;
对于记录类型“大小”使用64;
对于“校准”类型的记录,使用4;
对于记录类型,请使用记录
种类在??范围0-1.
0范围内的X。。31;
Y在4范围0。。31;
S在0范围0。。63;
结束记录;
对于整数2’大小,使用96;
对于整数2'对齐,使用4;
对于整数2,请使用记录
种类在0范围0。。7.
X在4范围内0。。31;
Y在8范围0。。31;
S在4范围0。。63;
结束记录;
一种可能是在嵌套包中声明Record\u 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中用于语言定义的方面,或由供应商用于供应商定义的方面”
声明未选中\u Union
是一个表示方面。因此,它应该被继承
说明接口方面,包括约定
,是表示方面<因此,应继承代码>按副本传递
我会准备一份bug报告。一种可能是在嵌套包中声明记录类型的操作,比如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中用于语言定义的方面,或由供应商用于供应商定义的方面”
声明未选中\u Union
是一个表示方面。因此,它应该被继承
说明接口方面,包括约定
,是表示方面<因此,应继承代码>按副本传递
我会准备一份bug报告。虽然你的陈述是正确的,但这并不能回答我的问题。除了警告之外,我还有其他证据证明派生类型不是未检查的联合(最小类型大小包括判别大小),所以我仍然想知道为什么不是这种情况,以及如何解决这个问题。顺便说一句,在这种情况下,上述错误执行是不可能的,因为两个变量包含相同的类型,因此不能用于未经检查的转换;这是一个Ada变体记录,在C中没有直接的等价物;此外,C\u Pass\u By\u Copy
对于具有该类型的参数没有意义。对不起,如果我