请考虑以下实验性 Ada 程序,该程序尝试创建具有明确定义的位字段的 32 位记录,创建一个并将其输出到文件流...
with System;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Streams.Stream_Io; use Ada.Streams.Stream_Io;
procedure Main is
type Bit is mod (2 ** 1);
type Opcode_Number is mod (2 ** 4);
type Condition_Number is mod (2 ** 4);
type Operand is mod (2 ** 9);
type RAM_Register is
record
Opcode : Opcode_Number;
Z : Bit;
C : Bit;
R : Bit;
I : Bit;
Cond : Condition_Number;
Rsvd_1 : Bit;
Rsvd_2 : Bit;
Dest : Operand;
Src : Operand;
end record;
for RAM_Register use
record
Opcode at 0 range 28 .. 31;
Z at 0 range 27 .. 27;
C at 0 range 26 .. 26;
R at 0 range 25 .. 25;
I at 0 range 24 .. 24;
Cond at 0 range 20 .. 23;
Rsvd_1 at 0 range 19 .. 19;
Rsvd_2 at 0 range 18 .. 18;
Dest at 0 range 9 .. 17;
Src at 0 range 0 .. 8;
end record;
for RAM_Register'Size use 32;
for RAM_Register'Bit_Order use System.High_Order_First;
-- ADA 2012 language reference 'full_type_declaration'
-- (page 758, margin number 8/3) for RAM_Register
pragma Atomic (RAM_Register);
-- 3 2 1 0
-- 10987654321098765432109876543210
-- OOOOzcriCONDrrDDDDDDDDDsssssssss
X : RAM_Register := (2#1000#,
2#1#,
2#1#,
2#1#,
2#1#,
2#1000#,
2#1#,
2#1#,
2#100000001#,
2#100000001#);
The_File : Ada.Streams.Stream_IO.File_Type;
The_Stream : Ada.Streams.Stream_IO.Stream_Access;
begin
begin
Open (The_File, Out_File, "test.dat");
exception
when others =>
Create (The_File, Out_File, "test.dat");
end;
The_Stream := Stream (The_File);
RAM_Register'Write (The_Stream, X);
Close (The_File);
end Main;
我在这里使用了信息:https://rosettacode.org/wiki/Object_serialization#Ada在这里:https://en.wikibooks.org/wiki/Ada_Programming/Attributes/%27Bit_Order (最后一个示例)创建上述内容。
运行代码并使用
xxd -g1 test.dat
检查输出给出以下 12 个字节的输出...00000000: 08 01 01 01 01 08 01 01 01 01 01 01 ............
问题:
如何将此 32 位记录写入或读取为 32 位流,观察所有位域位置?想象一下,我在 RS-232 端口上与微 Controller 通信,每个位都需要在正确的时间准确地位于正确的位置。语法
for RAM_Register use record...
似乎对如何'Write
没有影响安排它的输出。如果我提供自己的
'Read
和 'Write
实现,不是直接与“for RAM_Register 使用记录...”代码相矛盾?
最佳答案
您可能必须将实例转换为无符号整数(通过未经检查的转换),然后将无符号整数写入流。 Write
的默认实现忽略表示子句(另见 RM 13 9/3 ):
For composite types, the Write or Read attribute for each component is called in canonical order, [...]
所以,添加
with Interfaces; use Interfaces;
with Ada.Unchecked_Conversion;
并定义
RAM_Register
作为 type RAM_Register is
record
Opcode : Opcode_Number;
Z : Bit;
C : Bit;
R : Bit;
I : Bit;
Cond : Condition_Number;
Rsvd_1 : Bit;
Rsvd_2 : Bit;
Dest : Operand;
Src : Operand;
end record with Atomic;
procedure Write
(Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : RAM_Register);
for RAM_Register'Write use Write;
for RAM_Register use
record
Opcode at 0 range 28 .. 31;
Z at 0 range 27 .. 27;
C at 0 range 26 .. 26;
R at 0 range 25 .. 25;
I at 0 range 24 .. 24;
Cond at 0 range 20 .. 23;
Rsvd_1 at 0 range 19 .. 19;
Rsvd_2 at 0 range 18 .. 18;
Dest at 0 range 9 .. 17;
Src at 0 range 0 .. 8;
end record;
for RAM_Register'Size use 32;
for RAM_Register'Bit_Order use System.High_Order_First;
-----------
-- Write --
-----------
procedure Write
(Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : RAM_Register)
is
function To_Unsigned_32 is
new Ada.Unchecked_Conversion (RAM_Register, Unsigned_32);
U32 : Unsigned_32 := To_Unsigned_32 (Item);
begin
Unsigned_32'Write (Stream, U32);
end Write;
这产生
$ xxd -g1 test.dat
00000000: 01 03 8e 8f ....
注意:比特顺序可能已经颠倒了,因为我不得不评论方面规范
for RAM_Register'Bit_Order use System.High_Order_First;
关于stream - Ada - 如何显式打包位字段记录类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58493193/