powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Вопрос по выравниванию
14 сообщений из 14, страница 1 из 1
Вопрос по выравниванию
    #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
Вопрос по выравниванию
    #39960793
rgreat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Что бы просто Variant не использовать?
...
Рейтинг: 0 / 0
Вопрос по выравниванию
    #39960801
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rgreat
Что бы просто Variant не использовать?
Структура приходит из внешнего мира
...
Рейтинг: 0 / 0
Вопрос по выравниванию
    #39960803
rgreat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_,

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

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

https://it.wikireading.ru/34858

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

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

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


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