У меня много программ, которые я пишу для своих личных целей в 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, на форуме которого вы находитесь) уже давно сдохли, вряд ли у них что то такое продвинутое есть.
Кстати, в 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.
Жаль! И даже странно.
Спасибо, посмотрю эти костыли.
В дельфи, краем глаза нагуглил, есть тип Variant, буду дальше изучать проблему. Просто для моих консольных задач хотелось что-нибудь попроще этого монстра Дельфи
begin
var o:object;
writeln(o);//nil, то есть ничего
o := 5;
writeln(o);//5
o := 'g';
writeln(o);//g
end.
Но вы не сможете так запечатать в ochar, а получить назад word. И я подозреваю что в делфи тоже. И про делфи я имел в виду что тот же костыль будет работать (наверное) потому что в делфи тоже есть атрибуты.
Можно сделать безопасно, но реализация такой системы как раз и порождает большие накладные расходы, т.е. в конечном счете делает код неэффективным. А надобность в этой экзотике очень спорна. Я нахлебался когда-то досыта этих чудес с фортрановским EQUIVALENCE.