请考虑以下代码:
My_Constant : constant := 2;
是" My_Constant"变量或C语言类宏,它在内存中有存储吗?
答案 0 :(得分:7)
请注意constant
仅表示您无法修改对象。它并不一定意味着在编译时已知常量的值。因此有三种情况需要考虑:
(1)具有类型的常量,其值在编译时是已知的:
My_Constant : constant Integer := 3;
在这种情况下,编译器没有理由为常量分配内存;它可以在看到My_Constant
时使用值3(并且可能在可能的情况下使用3作为指令的直接操作数;如果它看到类似My_Constant * 2
的内容,那么它可以使用值6作为即时操作数)。编译器允许为常量分配内存,但我不认为任何像样的编译器都会这样做,在一个简单的情况下使用较小的数字。如果它是一个非常大的数字,不适合立即操作数,那么为数字某处分配空间可能更有意义(如果它可以节省代码空间的方式) )。
在更复杂的情况下:
My_Record_Constant : constant Rec := (Field_1 => 100, Field_2 => 201, Field_3 => 44);
在这里,一个好的编译器可以决定是否根据它的使用方式将常量存储在内存中。如果唯一的用途是访问单个字段(My_Record_Constant.Field_1
),则编译器可以用整数值替换它们,就像它们是整数常量一样,并且不需要将整个记录存储在内存中。
但是,使用aliased
会导致任何常量被强制进入内存:
My_Constant : aliased constant Integer := 3;
现在必须分配内存,因为程序可以说My_Constant'Access
(访问类型必须是access constant Integer
)。
(2)在编译时未知其值的常量:
My_Constant : constant Integer := Some_Function_Call (Parameter_1);
当详细说明整数的声明时,该函数被称为一次。由于它不是宏扩展,因此My_Constant
的使用不会生成对函数的调用。例如:
procedure Some_Procedure is
My_Constant : constant Integer := Some_Function_Call (Parameter_1);
begin
Put_Line (Integer'Image (My_Constant));
Put_Line (Integer'Image (My_Constant));
end Some_Procedure;
每次调用Some_Function_Call
时都会调用{p> Some_Procedure
,但它被称为一次,而不是两次或三次。
最有可能的是,这需要将值存储在内存中以保存函数结果,因此将为My_Constant
分配空间。 (这仍然不是必需的。如果一个好的优化编译器能够以某种方式判断Some_Function_Call
将返回一个已知值,它就可以使用该信息。)
(3)命名号码。这是您拥有的示例,其中没有类型:
My_Constant : constant := 2;
语言规则说必须在编译时知道该值。这相当于每次看到My_Constant
时使用该数字,所以它与您在Ada中获得的C宏最接近。但效果基本上与(1)中的相同[除了对类型兼容性的限制较少]。编译器可能不会为它分配空间,但它可能会为更大的值分配空间。请注意,此语法仅允许用于数值(整数或实数)。
答案 1 :(得分:0)
上面选项(1)的另一个变体是一个常数数组。
primes : constant array(integer range <>) of integer := (1, 3, 5, 7, 11, 13, 17, 19, 23);
如果编译器可以看到索引正在访问它,则必须存储该数组。 我怀疑编译器编写者会尝试和特殊情况下任何其他模糊的角落条件来节省一些内存 - 他们有足够的其他特殊角落案例在Ada中担心!