Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Вопрос по выравниванию / 14 сообщений из 14, страница 1 из 1
22.05.2020, 16:42
    #39960791
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по выравниванию
Есть такая структура
Код: pascal
1.
2.
3.
4.
5.
6.
  TBaseMsg = record
    Arg1Val: Integer;
    Arg1Null: WordBool;
    Arg2Val: SmallInt;
    Arg2Null: WordBool;
  end;

хочу оптимизировать запись этой структуры и объявляю ее так
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
  TGenRec<T> = record
    Val: T;
    IsNull: WordBool;
  end;

  TTestMsg = record
    Arg1: TGenRec<Integer>;
    Arg2: TGenRec<Smallint>;
  end;

в моем понимании я ничего не изменил. Но теперь перестало читаться поле Arg2.Val.

Тест
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
procedure Test(AData: Pointer);
var
  LInArgs1: PTestMsg absolute AData;
  LInArgs2: PBaseMsg absolute AData;
  LBuf: string;
  Li: Integer;
begin
    Writeln(LLog, '----- Use generic record --------');
    Writeln(LLog, 'Size: ', SizeOf(LInArgs1^));

    SetLength(LBuf, SizeOf(LInArgs1^) * 2);
    BinToHex(LInArgs1, PChar(LBuf), SizeOf(LInArgs1^));
    // Форматируем вывод по 4 октета
    LBuf := LBuf.PadRight((Length(LBuf) + 7) and not 7);
    Li := Length(LBuf);
    while Li > 8 do begin
      Dec(Li, 8);
      Insert(' ', LBuf, Li);
    end;
    Writeln(LLog, 'Data: ', LBuf);
    Writeln(LLog, 'Arg1: ', LInArgs1^.Arg1.Val);
    Writeln(LLog, 'Arg2: ', LInArgs1^.Arg2.Val);

    Writeln(LLog, '----- Use base record --------');
    Writeln(LLog, 'Size: ', SizeOf(LInArgs2^));

    SetLength(LBuf, SizeOf(LInArgs2^) * 2);
    BinToHex(LInArgs2, PChar(LBuf), SizeOf(LInArgs2^));
    LBuf := LBuf.PadRight((Length(LBuf) + 7) and not 7);
    Li := Length(LBuf);
    while Li > 8 do begin
      Dec(Li, 8);
      Insert(' ', LBuf, Li);
    end;
    Writeln(LLog, 'Data: ', LBuf);
    Writeln(LLog, 'Arg1: ', LInArgs2^.Arg1Val);
    Writeln(LLog, 'Arg2: ', LInArgs2^.Arg2Val);
end;

Вывод
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
----- Use generic record --------
Size: 12
Data: 1000000 00000FF0 000000000
Arg1: 16
Arg2: 0
----- Use base record --------
Size: 12
Data: 1000000 00000FF0 000000000
Arg1: 16
Arg2: 255
Правильное значение аргументов 16, 255. Где я не прав? Почему Smallint уезжает?
Полный тест
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
procedure Test(AData: Pointer);
var
  LInArgs1: PTestMsg absolute AData;
  LInArgs2: PBaseMsg absolute AData;
  LFileName: string;
  LLog: TextFile;
  LBuf: string;
  Li: Integer;
begin
  LFileName := ChangeFileExt(GetModuleName(HInstance), '.log');
  AssignFile(LLog, LFileName);
  if FileExists(LFileName) then
    Append(LLog)
  else
    Rewrite(LLog);
  try
    Writeln(LLog, '==================');
    Writeln(LLog, '----- Use generic record --------');
    Writeln(LLog, 'Size: ', SizeOf(LInArgs1^));

    SetLength(LBuf, SizeOf(LInArgs1^) * 2);
    BinToHex(LInArgs1, PChar(LBuf), SizeOf(LInArgs1^));
    LBuf := LBuf.PadRight((Length(LBuf) + 7) and not 7);
    Li := Length(LBuf);
    while Li > 8 do begin
      Dec(Li, 8);
      Insert(' ', LBuf, Li);
    end;
    Writeln(LLog, 'Data: ', LBuf);
    Writeln(LLog, 'Arg1: ', LInArgs1^.Arg1.Val);
    Writeln(LLog, 'Arg2: ', LInArgs1^.Arg2.Val);

    Writeln(LLog, '----- Use simple record --------');
    Writeln(LLog, 'Size: ', SizeOf(LInArgs2^));

    SetLength(LBuf, SizeOf(LInArgs2^) * 2);
    BinToHex(LInArgs2, PChar(LBuf), SizeOf(LInArgs2^));
    LBuf := LBuf.PadRight((Length(LBuf) + 7) and not 7);
    Li := Length(LBuf);
    while Li > 8 do begin
      Dec(Li, 8);
      Insert(' ', LBuf, Li);
    end;
    Writeln(LLog, 'Data: ', LBuf);
    Writeln(LLog, 'Arg1: ', LInArgs2^.Arg1Val);
    Writeln(LLog, 'Arg2: ', LInArgs2^.Arg2Val);
    Writeln(LLog, '==================');
  finally
    CloseFile(LLog);
  end;
end;


С уважением, Vasilisk
...
Рейтинг: 0 / 0
22.05.2020, 16:47
    #39960793
rgreat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по выравниванию
Что бы просто Variant не использовать?
...
Рейтинг: 0 / 0
22.05.2020, 16:56
    #39960801
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по выравниванию
rgreat
Что бы просто Variant не использовать?
Структура приходит из внешнего мира
...
Рейтинг: 0 / 0
22.05.2020, 17:01
    #39960803
rgreat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по выравниванию
_Vasilisk_,

А что переложить мешает?
...
Рейтинг: 0 / 0
22.05.2020, 17:15
    #39960806
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по выравниванию
rgreat
А что переложить мешает?
Еще раз. TBaseRec, где поля идут подряд, работает именно так, как нужно. Мне не понятно, почему не работает с вложенными записями.

Вопрос не как сделать, а почему не работает
...
Рейтинг: 0 / 0
22.05.2020, 17:20
    #39960807
zedxxx
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по выравниванию
Delphi 10.3.3 работает как ожидается:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

type
  TGenRec<T> = record
    Val: T;
    IsNull: WordBool;
  end;

  TTestMsg = record
    Arg1: TGenRec<Integer>;
    Arg2: TGenRec<Smallint>;
  end;
  PTestMsg = ^TTestMsg;

procedure PrintData(const AData: Pointer);
var
  P: PTestMsg absolute AData;
begin
  Writeln(P.Arg1.Val, ' ', P.Arg1.IsNull);
  Writeln(P.Arg2.Val, ' ', P.Arg2.IsNull);
end;

procedure DoTest;
var
  I: Integer;
  P: Pointer;
  VMsg: TTestMsg;
begin
  I := SizeOf(VMsg);

  FillChar(VMsg, I, $EE);

  VMsg.Arg1.Val := 10;
  VMsg.Arg1.IsNull := False;

  VMsg.Arg2.Val := 20;
  VMsg.Arg2.IsNull := False;

  P := @VMsg;
  PrintData(P);
end;

begin
  try
    DoTest;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.



...
Рейтинг: 0 / 0
22.05.2020, 17:30
    #39960810
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по выравниванию
zedxxx
Delphi 10.3.3 работает как ожидается:
Тест некорректный. Должно быть так
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
procedure DoTest;
var
  I: Integer;
  P: Pointer;
  VMsg: TBaseMsg;
begin
  I := SizeOf(VMsg);

  FillChar(VMsg, I, $EE);

  VMsg.Arg1Val := 10;
  VMsg.Arg1IsNull := False;

  VMsg.Arg2Val := 20;
  VMsg.Arg2IsNull := False;

  P := @VMsg;
  PrintData(P);
end;
...
Рейтинг: 0 / 0
22.05.2020, 17:30
    #39960811
zedxxx
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по выравниванию
А вот дамп памяти с вашими значениями:

10 00 00 00 00 00 EE EE FF 00 00 00

так что дело, действительно, в выравнивании. В памяти структура теперь представляется как

4 - Integer
2 - WordBool
2 - Word - мусор
2 - SmallInt
2 - WordBool

а с обычной структурой оно выравнивалось вот так:

4 - Integer
2 - WordBool
2 - SmallInt
2 - WordBool
2 - Word - мусор
...
Рейтинг: 0 / 0
22.05.2020, 17:46
    #39960813
rgreat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по выравниванию
_Vasilisk_
zedxxx
Delphi 10.3.3 работает как ожидается:
Тест некорректный. Должно быть так
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
procedure DoTest;
var
  I: Integer;
  P: Pointer;
  VMsg: TBaseMsg;
begin
  I := SizeOf(VMsg);

  FillChar(VMsg, I, $EE);

  VMsg.Arg1Val := 10;
  VMsg.Arg1IsNull := False;

  VMsg.Arg2Val := 20;
  VMsg.Arg2IsNull := False;

  P := @VMsg;
  PrintData(P);
end;


Хотя-бы Packed Record сделай.
...
Рейтинг: 0 / 0
22.05.2020, 17:49
    #39960814
X-Cite
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по выравниванию
Можно полагаться только на явное выравнивание, которое вы указали. Все что определяется автоматически в целях оптимизации - может в любой момент времени измениться.
...
Рейтинг: 0 / 0
22.05.2020, 18:05
    #39960819
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по выравниванию
rgreat
Хотя-бы Packed Record сделай.
Для кого именно?
zedxxx
а с обычной структурой оно выравнивалось вот так:
Задаю вопрос третий раз. Почему два байта мусора прыгают по структуре?
...
Рейтинг: 0 / 0
22.05.2020, 18:09
    #39960822
rgreat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по выравниванию
_Vasilisk_,

https://it.wikireading.ru/34858

Просвещайся.
...
Рейтинг: 0 / 0
22.05.2020, 18:24
    #39960827
zedxxx
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по выравниванию
Почему два байта мусора прыгают по структуре?
Странный вопрос. Потому что вложенная структура тоже выравнивается.

Packed надо объявлять у всех структур, а там где ты предполагаешь, что должен быть мусор, пропиши его руками. Тогда не будет никаких сюрпризов.
...
Рейтинг: 0 / 0
22.05.2020, 18:25
    #39960828
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по выравниванию
_Vasilisk_Для кого именно?

Ни для кого не надо, совсем всё съедет.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Вопрос по выравниванию / 14 сообщений из 14, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]