Простая замена вариантного типа в исходных кодах Borland Pascal

Здравствуйте!

У меня много программ, которые я пишу для своих личных целей в Borland Pascal (редакторы, архиваторы/разархиваторы, сбощики/разборщики, компиляторы/декомпиляторы ресурсов одной компьютерной игры). Решил перевести свои проекты на Win-платформу. Для начала решил попробовать PascalABC, и сразу же столкнулся с тем, что в PascalABC отсутствуют вариантные типы переменных (record case). А все мои проекты используют именно этот тип, на нём основа моего кода.

Можно ли как-то легко заменить этот тип без глобального перелопачивания кода всех моих программ, или стоит забыть PascalABC, и поискать другие варианты (Delphi, FreePascal, что-нибудь ещё)?

А можете объяснить как этот тип работает в борланде, что не искать по всему интернету?

Попробую.

type tkind = (tbt,tcht);
	TUnionSource=record case kind: tkind of
		tbt: (UBS:byte);
		tcht: (UChS:char);
	end;
var
   USource:TUnionSource;

где tbt и tcht на самом деле один и тот же байт, только для типизированного паскаля упрощается его (байта) обработка, не надо туда-сюда его конвертировать, из byte в char, и обратно.

Например, считываю в USource.tbt (byte) файла, а затем анализ и обработку провожу с USource.tcht (char). Закончив обработку tcht, записываю в файл tbt.

На самом деле, код гораздо сложнее, ещё в процессе обработки (в том же декомпиляторе) постоянно “гуляют” между собой tbt и tcht.

Форматирование слетает…

Классика жанра - “записи с вариантами”. Очень неэффективная реализация. Посмотрите у Вирта.в книге.

Выделяйте код так:
```
код
```

Этот знак находится за Ё в англ раскладке.
Так же есть однострочный код: `однострочный код`
выглядит как однострочный код

У меня эти tbt и tcht в ходе анализа и преобразований используются тысячи раз, и что, мне эти тысячи раз гонять процедуры преобразования типов? Да ну, ерунда какая-то. Чем мне в этой задаче поможет Вирт? По моему, в данном случае вариантная запись - самый эффективный способ обработки содержимого бинарного файла скриптов.

А то есть как union в C++? Ну, во всём .Net нету его, но есть костыльная замена через атрибуты:

uses System.Runtime.InteropServices;

type
  [StructLayout(LayoutKind.&Explicit)]
  r1=record
    
    public [FieldOffset(0)] int:integer;
    public [FieldOffset(0)] float:single;
    
  end;

begin
  var a:r1;
  a.int := 5;
  writeln(a.float);
end.

В делфи это должно работать, наверное, а фри паскаль, PascalABC (не путать с PascalABC.Net, на форуме которого вы находитесь) уже давно сдохли, вряд ли у них что то такое продвинутое есть.

А причем тут Вирт и Вы? К Вирту я отсылал @Sun_Serega, чтобы он “не искал по всему интернету”.

Найти в книжке ещё сложнее чем в интернете)))

Там есть такой подраздел ))) Ну и книжка в Интернете есть сама.

А что за игра, если не секрет? Если хотите - можете ещё выложить в проекты на PascalABC.Net если переведете на этот язык.

Не переведет, если не мыслит себе жизни без вариантных записей. Блин, как я почти полвека активного программирования без них прожил?

Кстати, в PascalABC.Net тип char занимает 2 байта, из за того что кодировка у него Unicode. Поэтому вторая переменная должна иметь тип word а не byte. Но, в .Net этот перевод вам вряд ли понадобится, потому что можно делать так:

begin
  var ch := 'g';
  var f := System.IO.File.Create('my file.txt');
  var bw := new System.IO.BinaryWriter(f);
  var tw := new System.IO.StreamWriter(f,System.Text.Encoding.UTF8);//допустим вы всё же хотите сохранять по 1 байту на символ, значит UTF8
  
  
  
  bw.Write(new byte[](//Можно записывать массив байтов (или по 1 байту) через BinaryWriter
    $01,
    $23,
    $45,
    $67,
    $89
  ));
  bw.Write(byte(5));//А вот так по 1 байту (это, конечно, медлинее если у вас уже готовый массив)
  bw.Write(5);//И числа тоже можно. На integer выделяется 4 байта, поэтому эта строчка добавит 4 байта в поток
  
  
  
  tw.Write(ch);//Можно записывать текст (или по 1 символу) через StreamWriter. При этом используется указаная раньше кодировка.
               //А стандартная кодировка, в котой сохранён символ в переменной ch это System.Text.Encoding.Unicode
  tw.Write(' test');
  
  
  
  f.Close;
end.

Точно, именно union, подзабыл термин.

Жаль! И даже странно. Спасибо, посмотрю эти костыли.

В дельфи, краем глаза нагуглил, есть тип Variant, буду дальше изучать проблему. Просто для моих консольных задач хотелось что-нибудь попроще этого монстра Дельфи :slight_smile:

Извините, я про “неэффективную” реализацию.

Ну так я и прошу совета, как легко перейти от них, чтоб в каждой строчке кода не гонять типы туда-сюда :slight_smile:

Нет, ну такое и в .Net есть:

begin
  var o:object;
  writeln(o);//nil, то есть ничего
  o := 5;
  writeln(o);//5
  o := 'g';
  writeln(o);//g
end.

Но вы не сможете так запечатать в o char, а получить назад word. И я подозреваю что в делфи тоже. И про делфи я имел в виду что тот же костыль будет работать (наверное) потому что в делфи тоже есть атрибуты.

Ну не зря же в .NET Framework от таких типов отказались.

Их не оказалось не из за неэффективности, а из за безопасности. Типа это не безопасно читать значение типа single из переменной типа integer.

Можно сделать безопасно, но реализация такой системы как раз и порождает большие накладные расходы, т.е. в конечном счете делает код неэффективным. А надобность в этой экзотике очень спорна. Я нахлебался когда-то досыта этих чудес с фортрановским EQUIVALENCE.