Только в стандартном стандарте ISO Ada, как пункт "Представление записи" + любая другая языковая функция (и) может быть переносима на процессоры с прямым и прямым порядком байтов?

Без использования нестандартного предложения ‡ Scalar_Storage_Order в последних выпусках GNAT, как, скажем, заголовок IPv4 можно переносимо представлять с помощью предложений представления записи вместе с любой комбинацией любых других языковых функций, так что "тот же" код работает как на процессорах с прямым порядком байтов, так и на процессорах с прямым порядком байтов, но передаваемых по проводам (например, через, скажем, полезную нагрузку кадра Ethernet) в том, что IETF называет сетевым байтовым порядком (это причудливое имя IETF для big-endian). В C "тот же" код может использовать макросы препроцессора для выполнения замены байтов на процессорах с прямым порядком байтов, но не должен использоваться на процессорах с прямым порядком байтов, но стандартный Ada не имеет препроцессора. В C++ "тот же" код мог бы использовать мета-шаблонное программирование (MTP) для выполнения замены байтов на процессорах с прямым порядком байтов, но быть неоперативным на процессорах с прямым порядком байтов, но в стандартной Аде отсутствует MTP.

(Кстати, почти такая же проблема возникает в драйвере устройства, когда процессор с прямым порядком байтов взаимодействует с регистром отображения памяти периферийной микросхемы с прямым порядком байтов, или наоборот: процессор с прямым порядком байтов взаимодействует с регистром отображения памяти ИС с прямым порядком байтов.)

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

Обратите внимание, как "PowerOf2Highest минус" и "обращение" битовых идентификаторов старшего порядкового номера из (из, в) порядка в (визуально, арифметически не реально) (до, из) порядка используются в части #2 байтового свопа как грубый эквивалент спада VHDL, который является ключевой частью того, как VHDL решит эту проблему разнородности. (VHDL является родственным языком для Ada83.)

Но теперь, как скрыть, какой член набора {Header_IPv4_Homogenous, Header_IPv4_Heterogenous} был выбран в качестве имени типа Header_IPv4_Portable в app-domain-code? Использовать дочерние пакеты?

‡ Scalar_Storage_Order был предложен в качестве потенциальной функции для следующего издания стандарта ISO Ada, но пока что нет официального спонсора, который бы выступал за предложение в комитете по стандартизации ISO, поэтому предложение по стандартизации могло бы куда-то упасть и погибнуть на корню. Кроме того, я буду использовать не-GNAT-компилятор Ada, поэтому использование функции, специфичной для GNAT, для меня недоступно.

0 ответов

Часть решения, описанного выше, была подготовлена ​​Норманом Коэном в 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 и правильно ее читать, она должна быть достаточной для обработки на основе потоков и намного проще, чем здесь.

Другие вопросы по тегам