使用存储管理器进行内存分配导致不是纯函数 (RM 13.1(22))

Memory allocation with storage manager leads to not pure function (RM 13.1(22))

将一些旧代码移植到较新的 CentOs Linux 机器上。 我正在使用带有几个标志的 linux gnat:

Default_Switches ("ada") use ("-fstack-check", "-g", "-gnatVr", "-gnato", "-gnatE", "-gnatwmuv", "-gnata", "-m32");

我有 gnat 版本:

gcc-gnat.i686   4.8.5-11.el7

所以这些是先决条件。 我现在有一个可以正常工作的自写存储管理器,由

调用
St_Wa.Alloc(StoragePool, BitSize)

现在我的问题是,老实说,我真的不明白为什么编译器会失败,所以如果能详细解释为什么它不起作用,我将不胜感激!

function AllocMem(StoragePool : in St_Wa.Mem_Pool_Type;
                  Option: in Option_Type) 
                  return Option_Ref is

 subtype New_Type is Option_Type (Option.Kind);

 New_Option : New_Type;

for New_Option use at St_Wa.Alloc( StoragePool => StoragePool, 
                                    BitSize => New_Type'Size)
begin 
    Bl_Bl.Move( ... sth happens here ... )
    return Pointer(New_Option'Address);
end AllocMem;

鉴于:

type Option_Type ( Kind : Option_Kind_Type := Marker) is
record
  Next : Option_Ref;
  case Kind is
    when First_Procedure => First_Procedure : First_Procedure_Type;
    when Sec_Procedure => Sec_Procedure : Sec_Procedure_Type;
  end case;
end record;

我收到以下错误:

invalid address clause for initialized object "New_Option"
function "Alloc" is not pure (RM 13.1 (22))

我收到这个错误是因为我有一个带有条件的类型的开关盒,因此大小只取决于种类吗?如何在不重写所有内容的情况下避免这种情况?

Do I get this error because I have a switch case in the type with conditions and therefore the size is only determined depending on kind?

没有。 LRM 中错误消息 (RM 13.1 (22)) 引用的段落内容如下:

An implementation need not support representation items containing nonstatic expressions, except that an implementation should support a representation item for a given entity if each nonstatic expression in the representation item is a name that statically denotes a constant declared before the entity.

现在,这里的表示项是对 Alloc 的调用,因为您的代码:

for New_Option use at St_Wa.Alloc(StoragePool => StoragePool, 
                                  BitSize => New_Type'Size);

的 Ada83 风格
for New_Option'Address use St_Wa.Alloc(StoragePool => StoragePool, 
                                       BitSize => New_Type'Size);

并且由于 Alloc (...) 是函数调用,它不是静态表达式,因为根据 RM 4.9,静态函数是:

  • a predefined operator whose parameter and result types are all scalar types none of which are descendants of formal scalar types;
  • a predefined concatenation operator whose result type is a string type;
  • an enumeration literal;
  • a language-defined attribute that is a function, if the prefix denotes a static scalar subtype, and if the parameter and result types are scalar.

由于Alloc 是上面的none,如RM 13.1 所述,实现不需要在表示项中支持它。然而,实际的错误消息告诉我们 "Alloc" 不是纯的 ,所以 GNAT 告诉它如果 Alloc 是纯的它会支持这个。

因此解决此问题的一种方法是使 Alloc 纯净,这意味着:将 pragma Pure; 添加到包含 Alloc 的包 St_Wa 中。这是否可能取决于包,它可能需要额外的更改。

如果这不可行,RM 13.1 (22) 以另一种方式暗示:如果非静态表达式表示在实体之前声明的常量,则应支持该表达式。因此,这应该有效:

My_Address : constant System.Address :=
  St_Wa.Alloc(StoragePool => StoragePool, BitSize => New_Type'Size);

New_Option : New_Type;

for New_Option use at My_Address;