Without utilizing the nonstandard‡ Scalar_Storage_Order clause in recent releases of GNAT, how can, say, the IPv4 header be portably represented via Record Representation Clause(s) in conjunction with any combination of any other language features, so that “the same” code works on both little-endian and big-endian processors but be emitted on the wire (e.g., via, say, the payload of an Ethernet frame) in what IETF calls network byte order (which is IETF's fancy name for big-endian). In C, “the same” code could utilize preprocessor macros to perform byte-swapping on little-endian processors, but be a no-op on big-endian processors, but standard Ada has no preprocessor. In C++, “the same” code could utilize meta-template programming (MTP) to perform byte-swapping on little-endian processors, but be a no-op on big-endian processors, but standard Ada lacks MTP.
(Btw, much the same issue arises in a device driver when a big-endian processor interfaces with a little-endian peripheral IC's memory-mapped register, or vice versa: little-endian processor interfaces with a big-endian IC's memory-mapped register.)
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
Note how “PowerOf2Highest minus” and ‘reversing’ the big-endian's bit ids from (from,to) order to [visually, not arithmetically really] (to,from) order are utilized in part #2 of the byte-swap as a rough equivalent of VHDL's downto, which is a key portion of how VHDL would solve this heterogenous-endianness problem. (VHDL is a cousin language to Ada83.)
But now, how to obfuscate which member of the set {Header_IPv4_Homogenous, Header_IPv4_Heterogenous} has been chosen as the type name Header_IPv4_Portable in app-domain-code? Use child packages?
‡ Scalar_Storage_Order has been proposed as a potential feature for the next edition of the ISO standard of Ada, but so far there is no official sponsor championing the proposal in the ISO standardization committee, so the proposal for standardization could whither & die on the vine. Plus I shall use a non-GNAT Ada compiler, so using the GNAT-specific feature is unavailable to me.