我的日常工作是使用安全关键的嵌入式系统。我还与客户就编写安全嵌入式代码的主题进行了一些教学/咨询。编程语言的问题总是出现,我们比较了 C、D、Ada、Erlang、Rust 等。
有一个练习我经常用于演示目的。这是一个简单的双线程程序,每个线程获取一个全局变量(初始化为 0),将其加 1 并替换它十次。然后我们推测变量在末尾可以具有的最大值 (20) 和它的最小值(我们通常在使用正式证明证明它可以是 2 之前决定 10)。
我演示的一件事是程序的 C 版本可以编译(危险),但 Rust 版本不能(好!)。今天我写了 Ada 版本,有两个惊喜我想征求意见。首先,我的程序:
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
task AddTenA;
task AddTenB;
-- Global variable
x : Natural := 0;
finished : array (0 .. 1) of Natural := (0, 0);
-- Make sure that the compiler doesn't remove
-- all the addition.
pragma Volatile (x);
task body AddTenA is
y : Integer;
begin
for I in 1 .. 10 loop
y …Run Code Online (Sandbox Code Playgroud) 我正在寻找风格指导。在 Python 中,异常被用作“正常”操作:
try:
z = x/y
except ZeroDivisionError:
z = 73.0 # set z if y is zero
Run Code Online (Sandbox Code Playgroud)
我们不是检查 y 是否接近零,而是进行除法并捕获异常。
这种类型的方法在 John Barnes 的“Programming in Ada 2012”中的 Ada 中有说明:
begin
Tomorrow := Day'Succ(Today);
exception
when Constraint_Error =>
Tomorrow := Day'First;
Run Code Online (Sandbox Code Playgroud)
但是,这本书接着说“这是一个非常糟糕的例子。异常应该用于很少发生的情况......”。
我是 Ada 的新手,像我们在 Python 中所做的那样,使用异常来避免 if 语句是一种好的 Ada 编程风格吗?或者异常真的只是在 Ada 中用于令人讨厌的事情?
一个初学者的问题,恐怕。我需要记录数组中特定元素的位置(索引)。考虑以下:
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
Ten : constant Positive := 10;
type ArrayIndex is new Positive range 1 .. Ten;
type MyRecord is record
firstItem : Integer;
secondItem : Integer;
end record;
TheRecords : array (1 .. Ten) of MyRecord;
indexOfElement50 : ArrayIndex := 1;
begin
-- set the values in TheRecords
for i in TheRecords'Range loop
TheRecords(i).firstItem := i * 10;
TheRecords(i).secondItem := i * 20;
end loop;
-- find which element of TheRecords has a …Run Code Online (Sandbox Code Playgroud) 以下是尝试用最少的代码产生我的问题(它不是一个有用的程序)。
我的问题是我想对依赖于私有变量的公共函数做一个先决条件。我必须在“私有”指标之前声明我的函数,并在该指标之后声明我的变量。这意味着我收到编译错误
question.ads:10:16: "secondPrivateVariable" 未定义问题.ads:10:40: "firstPrivateVariable" 未定义
我曾尝试将占位符定义放在函数上方,但随后出现有关定义冲突的编译错误。
package Problem is
pragma Elaborate_Body (Problem);
function publicAPI(which : Positive) return Natural with
Pre => secondPrivateVariable > firstPrivateVariable;
-- should only be called when second > first
private
-- the following variables are used by many procedures and
-- should be kept private
firstPrivateVariable : Natural := 7;
secondPrivateVariable : Natural := 465;
end Problem;
Run Code Online (Sandbox Code Playgroud)
欢迎任何帮助。
以下程序 (main.adb) 将无法编译,并出现错误:
main.adb:10:15: expected private type "ThreadName" defined at config.ads:5
main.adb:10:15: found private type "Ada.Strings.Unbounded.Unbounded_String"
main.adb:11:45: expected private type "Ada.Strings.Unbounded.Unbounded_String"
main.adb:11:45: found private type "ThreadName" defined at config.ads:5
Run Code Online (Sandbox Code Playgroud)
然而,当我添加一个“使用配置;” 条款并删除配置。在 main.adb 中 MyName 声明的前缀,它编译干净并正常工作。我明白使用“use”子句只是为了让我避免使用名称空间前缀,但它似乎还有很多作用。谁能解释一下?
文件 config.ads 包含
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
package Config is
type ThreadName is new Unbounded_String;
end Config;
Run Code Online (Sandbox Code Playgroud)
我的 main.adb 包含:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Config;
procedure Main is
MyName : Config.ThreadName;
begin
MyName := To_Unbounded_String ("Chris");
Put_Line ( "The name …Run Code Online (Sandbox Code Playgroud) 在 C 中,使用某种形式的 unsigned char 或 int 位来表示非排他条件是很常见的,并且通过使用 & | 和 ~ 操作符,效率极高。根据我有限的 Ada 经验,Ada 中的等效项如下面的代码所示。
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
type Colours is (Red, Green, Blue, Orange, Yellow, Purple);
type BitFieldType is array (Colours) of Boolean;
pragma Pack (BitFieldType);
RedBitField : constant BitFieldType := (Red => True, others => False);
GreenBitField : constant BitFieldType := (Green => True, others => False);
BlueBitField : constant BitFieldType := (Blue => True, others => False);
OrangeBitField : constant BitFieldType := …Run Code Online (Sandbox Code Playgroud) 我经常发现我需要指定一个变量从具有某种物理意义的范围(例如,SoC 上的特定核心)获取值。但我还需要能够将其设置为“无”,这意味着“目前它不持有真正的核心标识符”。我通常使用下面给出的两种模式之一来实现此目的,但每种模式都有缺点:
第一个需要定义额外的(而且确实不必要的)类型。
第二个要求手动保持两个字段(值和定义该值是否有效的字段)对齐。编译器无法检查这种对齐方式。
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
-- We want to specify a Unit Identifier in the range 1 .. 10.
-- However, sometimes we need to say that the Unit Identifier
-- being stored is invalid.
--
-- The first way of doing this is to define an extended range
-- and an Invalid Identifier.
type Extended_Core_Identifier is new Natural range 0 .. 10;
subtype Core_Identifier is Extended_Core_Identifier range 1 .. 10;
Invalid_Core : constant …Run Code Online (Sandbox Code Playgroud) ada ×7