Записи на Паскале смешивание слов и байтов в записях работает не так, как ожидалось

#delphi #record #pascal

Вопрос:

Мои данные выглядят так (один байт каждые два» -«):

  ---- -- ---- ---- 
|0840|0C|00AD|0840|
 ---- -- ---- ---- 
 

Если я использую этот код: НЕПРАВИЛЬНО

 Type TAlarmasRATP = record
   Funcion   : word;
   Instancia : byte;
   Err_0     : word;
   Err_1     : word;
end;
 

Функция = 4008, Экземпляр = 0C, Err_0 = 08AD, Err_1 = 0040

Если я использую этот код: ПРАВИЛЬНО

 Type TAlarmasRATP = record
   Funcion   : word;
   Instancia : byte;
   Err_0     : array [0..1] of byte;
   Err_1     : array [0..1] of byte;
end;
 

Функция = 4008, Экземпляр = 0C, Err_0 = AD00, Err_1 = 4008

Почему первый не работает?

Комментарии:

1. Попробуй с собой packed record .

2. @Оливье большое спасибо, это решает проблему.

Ответ №1:

При использовании типа записи поля выравниваются в соответствии со спецификацией Внутренние форматы данных — Типы записей:

Тип выравнивание в байтах (32-битная платформа)
порядковый размер типа (т. е. 1 для Byte , 2 для Word , 4 для Cardinal или 8 для Int64 )
реальный 2 для Real48 , 4 для Single , 8 для Double и Extended
ShortString 1
Array То же, что и тип элемента массива
Record Наибольшее выравнивание полей в записи
Set Размер типа (1, 2 или 4), в противном случае всегда 1
все остальные Определяется {$A} директивой

Это означает: в первом объявлении записи Err_0 поле будет выровнено по Word границе и добавит один байт заполнения после Instancia поля.

Во втором объявлении записи Err_0 поле будет выровнено по Byte границе, поскольку оно представляет собой массив Byte , и после поля не будет отступа Instancia . Поскольку запись не упакована, в конце структуры будет вставлен байт заполнения, поэтому размеры записей в обоих случаях будут округлены до 8.

Если вы используете packed ключевое слово, все поля в записи будут упакованы до границы байта, а размер записи будет точно соответствовать сумме размеров полей без заполнения в конце.

Для того, чтобы иметь размер записи 7, вы можете просто объявить:

 type TAlarmasRATP = packed record
   Funcion   : Word;
   Instancia : Byte;
   Err_0     : Word;
   Err_1     : Word;
end;
 

Однако, если вам нужен размер 8, вам следует вручную добавить байт заполнения в конце, определив просто другое поле, которое вы никогда не используете:

 type TAlarmasRATP = packed record
   Funcion   : Word;
   Instancia : Byte;
   Err_0     : Word;
   Err_1     : Word;
   Padding   : Byte;  // Unused
end;