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

У меня эти 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.

Спасибо! Но это всё равно означает, что придётся полностью переделывать весь имеющийся код. Гигантская работа, и как говорится: “овчинка выделки не стоит”. Придётся видимо под ДОСом оставаться :frowning:

Старую собаку не научишь новым штукам.

Может, проще это пристрелить, чтобы не мучиться? ))

А разве union так часто нужен?

В моих проектах переменные этого типа почти в каждой строчке кода (выше писал).

Нет, это я услышал, но зачем? Мне за всё время сколько я программировал - такое меньше 10 раз понадобилось…

Компилятор/декомпилятор. В исходном бинарном файле всё вперемешку же. Примерно так: Из этого

Z*level5.mazД°party has gained 800 points of experience.
ю ю8·ш
ю юs·їыю юА·їёїЁёїЁёїЁёЎaуЎ
у ўу

получть это

[Part 1]
{1A2A}		;Смещение, с которого начинается Part 5 (разумеется за вычетом -0Ah)
"level5.maz", 00, 00 ;Maze name (12 байт, после первого $00 байты игнорируются)
"blue", 00, "5.maz", 00, 00 ;VCN/VMP name (12 байт, после первого $00 байты игнорируются)
"blue", 00, "5.maz", 00, 00 ;Palette name (12 байт, после первого $00 байты игнорируются)
02, 00, FF, 03			;Nb of doors and doorknobs (???)
02, 00, 00, 32, 00			;Max monster / tdiff etc (???)
01			;Number of procedure for extraction of monster picture (???)
"dwarf", 00, ".maz", 00, 00 ;Name Of Monster pic CPS file (12 байт, после первого $00 байты игнорируются)
02			;Number of procedure for extraction of monster picture (???)
"spider", 00, "maz", 00, 00 ;Name Of Monster pic CPS file (12 байт, после первого $00 байты игнорируются)
00, 19			;Timer0 | Timer 1| Timerdiff (in Ticks)
01, 0F			;Timer0 | Timer 1| Timerdiff
FF			;End of Timer

А потом, после редактирования, скомпилировать назад в бинарный файл.

Ну, вот участок декомпилятора (переменные ubd и uchd):

with UDest do begin
{Алгоритм bytes2string
        b1 - текущая позиция в строке (от 0);
        b2 - 0: предыдущий символ был не буквой, 1: предыдущий символ был буквой}
	b1:=0;for j:=1 to 12 do begin
	read(fn1b,ubd);
	case ubd of
	0..31,127,176..223, 242..255: begin
		if b1=0 then write(fn2,dec1hex(ubd))
		else
			if b2=0 then write(fn2,', '+dec1hex(ubd))
			else write(fn2,'", '+dec1hex(ubd));
	b2:=0 end
	else begin
		if b1=0 then begin write(fn2,'"'+uchd);if uchd='"' then write(fn2,'"') end
		else
			if b2=0 then begin write(fn2,', "'+uchd);if uchd='"' then write(fn2,'"') end
			else begin write(fn2,uchd); if uchd='"' then write(fn2,'"') end;
	b2:=1 end
	end;{case}
	inc(b1);
	end;{for j}