如果不在最近版本的 GNAT 中使用非标准‡ Scalar_Storage_Order 子句,如何通过记录表示子句与任何其他语言功能的任意组合一起可移植地表示 IPv4 标头,以便"相同"的代码在小端和大端处理器上都有效,但在网络上发出(例如,通过, 比如说,以太网帧的有效载荷(,IETF称之为网络字节顺序(这是IETF对大端序的花哨名称(。 在 C 语言中,"相同"代码可以利用预处理器宏在小端处理器上执行字节交换,但在大端处理器上是无操作的,但标准 Ada 没有预处理器。 在C++中,"相同"代码可以利用元模板编程(MTP(在小端处理器上执行字节交换,但在大端处理器上是无操作的,但标准Ada缺乏MTP。
(顺便说一句,当大端处理器与小端外设 IC 的内存映射寄存器接口时,设备驱动程序中会出现大致相同的问题,反之亦然:小端处理器与大端 IC 的内存映射寄存器接口。
BytesPerWord : constant := 4;
BitsPerByte : constant := 8;
PowerOf2Highest : constant := BytesPerWord*BitsPerByte - 1; -- part #1 of byte-swap
type Header_IPv4 is record
Version : integer range 0 .. F#16;
IHL : integer range 0 .. F#16;
TOS : integer range 0 .. FF#16;
Length : integer range 0 .. FF#16;
Ident : integer range 0 .. FFFF#16;
Flags : integer range 0 .. 7#16;
Frag_Offs : integer range 0 .. 1FFF#16;
end record;
type Header_IPv4_Homogenous is new Header_IPv4;
for Header_IPv4_Homogenous use record -- Good-to-go for big-endian processors
Version at 0*BytesPerWord range 0 .. 3;
IHL at 0*BytesPerWord range 4 .. 7;
TOS at 0*BytesPerWord range 8 .. 15;
Length at 0*BytesPerWord range 16 .. 31;
Ident at 1*BytesPerWord range 0 .. 15;
Flags at 1*BytesPerWord range 16 .. 18;
Frag_Offs at 1*BytesPerWord range 19 .. 31;
end record;
for Header_IPv4_Homogenous'Alignment use 4;
for Header_IPv4_Homogenous'Bit_Order use High_Order_First;
type Header_IPv4_Heterogenous is new Header_IPv4;
for Header_IPv4_Heterogenous use record -- Good-to-go??? for little-endian processors?
Version at 0*BytesPerWord range PowerOf2Highest- 3 .. PowerOf2Highest- 0; -- p
IHL at 0*BytesPerWord range PowerOf2Highest- 7 .. PowerOf2Highest- 4; -- a
TOS at 0*BytesPerWord range PowerOf2Highest- 15 .. PowerOf2Highest- 8; -- r
Length at 0*BytesPerWord range PowerOf2Highest- 31 .. PowerOf2Highest- 16; -- t
Ident at 1*BytesPerWord range PowerOf2Highest- 15 .. PowerOf2Highest- 0; --
Flags at 1*BytesPerWord range PowerOf2Highest- 18 .. PowerOf2Highest- 16; -- #
Frag_Offs at 1*BytesPerWord range PowerOf2Highest- 31 .. PowerOf2Highest- 19; -- 2
end record;
for Header_IPv4_Heterogenous'Alignment use 4;
for Header_IPv4_Heterogenous'Bit_Order use Low_Order_First; -- part #3 of byte-swap
请注意,在字节交换的第 #2 部分中,如何将"PowerOf2Highest 减去"和"反转"大端的位 ID 从(从,到(顺序到 [视觉上,而不是算术上](从(顺序,作为 VHDL 的 downto 的粗略等价物,这是 VHDL 如何解决这个异构字节序问题的关键部分。(VHDL是Ada83的表亲语言。
但是现在,如何混淆集合{Header_IPv4_Homogenous,Header_IPv4_Heterogenous}的哪个成员被选为应用程序域代码中的类型名称Header_IPv4_Portable? 使用子包?
‡ Scalar_Storage_Order已被提议作为下一版 Ada 标准的潜在功能,但到目前为止,ISO 标准化委员会还没有官方赞助商支持该提案,因此标准化提案可能会在藤蔓上凋零。 另外,我将使用非GNAT Ada编译器,因此我无法使用GNAT特定的功能。
上述解决方案的部分是由诺曼·科恩在 ada-auth.org/ai-files/grab_bag/bitorder.pdf 差不多 20 年前,但是 这里和他的文件中都缺少的是交换的方式 在正确的记录表示条款中,例如,不同的子项 各种 Ada 编译器中的包。如何做那个子包 所有 Ada 编译器中的条件链接是我正在寻找的 现在。
传统的方法是通过多个文件,项目经理在编译完成后提供适当的文件。
也许我们可以使用另一种方法;我认为以下内容应该有效,我已经编译了它,但还没有测试它:
Package IPv4 is
Type Header_IPv4 is private;
Function Version ( Object : Header_IPv4 ) return Integer;
Function IHL ( Object : Header_IPv4 ) return Integer;
Function TOS ( Object : Header_IPv4 ) return Integer;
Function Length ( Object : Header_IPv4 ) return Integer;
Function Ident ( Object : Header_IPv4 ) return Integer;
Function Flags ( Object : Header_IPv4 ) return Integer;
Function Frag_Offs ( Object : Header_IPv4 ) return Integer;
-- If you need to write fields, use:
-- Procedure Field ( Object : in out Header_IPv4; Value : Integer );
Private
Header_Size : Constant := 7 * (4*8); -- 7 Integers of 4-bytes.
type Base_IPv4 is record
Version : integer range 0 .. 16#F#;
IHL : integer range 0 .. 16#F#;
TOS : integer range 0 .. 16#FF#;
Length : integer range 0 .. 16#FF#;
Ident : integer range 0 .. 16#FFFF#;
Flags : integer range 0 .. 16#7#;
Frag_Offs : integer range 0 .. 16#1FFF#;
end record
with Size => Header_Size, Object_Size => Header_Size;
type Header_IPv4 is null record
with Size => Header_Size, Object_Size => Header_Size;
End IPv4;
Package Body IPv4 is
Package Internal is
Use System;
BytesPerWord : constant := 4;
BitsPerByte : constant := 8;
PowerOf2Highest : constant := BytesPerWord*BitsPerByte - 1; -- part #1 of byte-swap
type Header_IPv4_Homogenous is new Base_IPv4;
for Header_IPv4_Homogenous use record -- Good-to-go for big-endian processors
Version at 0*BytesPerWord range 0 .. 3;
IHL at 0*BytesPerWord range 4 .. 7;
TOS at 0*BytesPerWord range 8 .. 15;
Length at 0*BytesPerWord range 16 .. 31;
Ident at 1*BytesPerWord range 0 .. 15;
Flags at 1*BytesPerWord range 16 .. 18;
Frag_Offs at 1*BytesPerWord range 19 .. 31;
end record;
for Header_IPv4_Homogenous'Alignment use 4;
for Header_IPv4_Homogenous'Bit_Order use High_Order_First;
type Header_IPv4_Heterogenous is new Base_IPv4;
for Header_IPv4_Heterogenous use record -- Good-to-go??? for little-endian processors?
Version at 0*BytesPerWord range PowerOf2Highest- 3 .. PowerOf2Highest- 0; -- p
IHL at 0*BytesPerWord range PowerOf2Highest- 7 .. PowerOf2Highest- 4; -- a
TOS at 0*BytesPerWord range PowerOf2Highest- 15 .. PowerOf2Highest- 8; -- r
Length at 0*BytesPerWord range PowerOf2Highest- 31 .. PowerOf2Highest- 16; -- t
Ident at 1*BytesPerWord range PowerOf2Highest- 15 .. PowerOf2Highest- 0; --
Flags at 1*BytesPerWord range PowerOf2Highest- 18 .. PowerOf2Highest- 16; -- #
Frag_Offs at 1*BytesPerWord range PowerOf2Highest- 31 .. PowerOf2Highest- 19; -- 2
end record;
for Header_IPv4_Heterogenous'Alignment use 4;
for Header_IPv4_Heterogenous'Bit_Order use Low_Order_First; -- part #3 of byte-swap
Function Convert_Heterogenous is new Ada.Unchecked_Conversion(
Source => Header_IPv4,
Target => Header_IPv4_Heterogenous
);
Function Convert_Homogenous is new Ada.Unchecked_Conversion(
Source => Header_IPv4,
Target => Header_IPv4_Homogenous
);
Function Convert_Heterogenous is new Ada.Unchecked_Conversion(
Source => Header_IPv4_Heterogenous,
Target => Header_IPv4
);
Function Convert_Homogenous is new Ada.Unchecked_Conversion(
Source => Header_IPv4_Homogenous,
Target => Header_IPv4
);
End Internal;
Function Convert( Object : Header_IPv4 ) return Base_IPv4 is
use Internal, System;
Begin
if Default_Bit_Order = High_Order_First then
Return Base_IPv4( Convert_Homogenous(Object) );
else
Return Base_IPv4( Convert_Heterogenous(Object) );
end if;
End Convert;
Function Version ( Object : Header_IPv4 ) return Integer is
(Convert(Object).Version);
Function IHL ( Object : Header_IPv4 ) return Integer is
(Convert(Object).IHL);
Function TOS ( Object : Header_IPv4 ) return Integer is
(Convert(Object).TOS);
Function Length ( Object : Header_IPv4 ) return Integer is
(Convert(Object).Length);
Function Ident ( Object : Header_IPv4 ) return Integer is
(Convert(Object).Ident);
Function Flags ( Object : Header_IPv4 ) return Integer is
(Convert(Object).Flags);
Function Frag_Offs ( Object : Header_IPv4 ) return Integer is
(Convert(Object).Frag_Offs);
End IPv4;
另一种选择可能是使用read
/write
属性,尽管这种形式不允许对 IPv4 类型的变量进行内存映射并正确读取它,但它应该足以进行基于流的处理,并且比这里简单得多。