ada - 使用不能被 8 整除的模块化类型时引发 Constraint_Error
问题描述
我遇到了一个问题,即在 Ada 中使用不能被系统整除的模块化类型Storage_Unit
(如运行时中定义的那样system.ads
)将Constraint_Error
在运行时在访问时引发 a。我最初在使用最小运行时间的裸机系统上工作时遇到了这个问题,同时尝试通过将 12 位数组覆盖在内存中的缓冲区上来从缓冲区读取 12 位值。有谁知道为什么会这样?
以下最小示例说明了我遇到的问题。我使用 AdaCore 的 GNAT 2019 对此进行了测试,并使用包含的zfp
运行时编译。使用标准运行时不会重现该问题。
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
----------------------------------------------------------------------------
-- Modular type with standard size divisible by 8.
----------------------------------------------------------------------------
type Type_One is mod 2 ** 16;
type Buffer_Type_One is array (1 .. 128) of Type_One;
----------------------------------------------------------------------------
-- Modular type with non-base 8 size.
----------------------------------------------------------------------------
type Type_Two is mod 2 ** 12;
type Buffer_Type_Two is array (1 .. 128) of Type_Two;
type Buffer is array (1 .. 256) of Character;
----------------------------------------------------------------------------
-- Example buffer.
----------------------------------------------------------------------------
Test_Buffer : Buffer := (others => ' ');
begin
----------------------------------------------------------------------------
-- Will not raise an exception.
----------------------------------------------------------------------------
Test_One :
declare
Buffer_One : Buffer_Type_One
with Import,
Convention => Ada,
Address => Test_Buffer'Address;
begin
Put_Line ("Testing type one");
for I in Natural range 1 .. 16 loop
Put_Line ("Test: " & Buffer_One (I)'Image);
end loop;
end Test_One;
----------------------------------------------------------------------------
-- Will raise a constraint error at runtime.
----------------------------------------------------------------------------
Test_Two :
declare
Buffer_Two : Buffer_Type_Two
with Import,
Convention => Ada,
Address => Test_Buffer'Address;
begin
Put_Line ("Testing type two");
for I in Natural range 1 .. 16 loop
Put_Line ("Test: " & Buffer_Two (I)'Image);
end loop;
exception
when Constraint_Error =>
Put_Line ("Constraint error encountered.");
end Test_Two;
end Main;
这是我用来编译这个例子的项目文件:
project Test is
for Object_Dir use "obj";
for Exec_Dir use "build";
for Create_Missing_Dirs use "True";
for Languages use ("Ada");
package Builder is
for Executable ("main.adb") use "test";
end Builder;
for Main use ("main.adb");
package Compiler is
for Default_Switches ("Ada") use (
"-gnat2012",
"-gnatwadehl",
"-gnatVa",
"-gnaty3abcdefhiklmnoprstux"
);
end Compiler;
for Runtime ("Ada") use "zfp";
end Test;
我似乎在 RM 中找不到任何可以说明为什么会发生这种情况的东西。
编辑:下面的西蒙赖特已经弄清楚为什么会发生这种情况。我幼稚的理解是,Buffer_Type_Two
在指定的内存地址上覆盖的一个实例会将这个位置的内存解释为 12 位值的序列。看来情况并非如此。似乎编译器将类型的大小四舍五入到 16 位,然后Constraint_Error
在从数组读取的 16 位值不符合 12 位类型时引发 a。
如果有人能想到一种更好的方法来以顺序方式从内存中的某个位置读取一系列 12 位值,我将不胜感激,谢谢。
解决方案
使用最近的 GNAT,您可以通过定义Buffer_Type_Two
为
type Buffer_Type_Two is array (1 .. 128) of Type_Two
with Pack;
ARM 13.2(9)警告说,对于 13 位值,这可能无法满足您的要求(不过,最近的 GNAT 会这样做)。
另一种选择是
type Buffer_Type_Two is array (1 .. 128) of Type_Two
with Component_Size => 12;
结果是
...
Testing type two
Test: 32
Test: 514
Test: 32
Test: 514
...
对于 13 位,无论采用哪种方法,
...
Testing type two
Test: 32
Test: 257
Test: 2056
Test: 64
Test: 514
Test: 4112
Test: 128
Test: 1028
Test: 32
...
但是,对于嵌入式目标,您需要使用-full-
运行时系统;对于其他人,正如上面@egilhh 所指出的,
ajxs.adb:14:09: packing of 12-bit components not supported by configuration
推荐阅读
- c++11 - 共享指针的分配/初始化差异
- python - 如何将更复杂的逻辑合并到 asyncio 期货列表理解中
- c# - 有没有办法查询 Workday API 以获取 PTO 请求?
- c# - 如果用户再次提交,是否在第一次提交更改值后禁用复选框(HTML)
- imaging - T1 中的 niftynet 文件名为空
- html - 如何在不使用绝对位置的情况下将徽标图像和菜单项对齐一行?
- google-analytics - 为什么我找不到我在数据源分析中使用的参数?
- .net - Angular7 Net2.2 信用卡处理应用
- angular - RxJS - 将发出的值映射到多个 Http 请求的组合输出
- wordpress - 将 Firebase 存储视频嵌入到 Wordpress 但隐藏 URL