SizeOf для структур

Форум для изучающих FPC и их учителей.

Модератор: Модераторы

SizeOf для структур

Сообщение ssnakess » 04.09.2023 03:38:32

Код: Выделить всё
     TTestRecord = record
        id:Byte;
        Data:Byte; 
     end;

SizeOf(TTestRecord) возвращает 2 - что логично и правильно
Код: Выделить всё
     TTestRecord = record
        id:Byte;
        Data:Integer; 

SizeOf(TTestRecord) возвращает 8 - как?? должно же быть 5!! :shock:
Далее еще интереснее
Код: Выделить всё
     TTestRecord = record
        id:Byte;
        Data:Int64; 

SizeOf(TTestRecord) возвращает 16 - как?? должно же быть 9!! :shock: :shock:

Код: Выделить всё
     TTestRecord = record
        id:Byte;
        Data:Pointer; 

SizeOf(TTestRecord) возвращает 16 - как?? :shock: :lol: :shock:

т.е. объявление тип Byte - в игнор, и выравниваем по самому большому размеру??
а как же тогда быть, если мне надо сохранить структуру в файл, где я хочу чтобы первое поле было все-таки 1 байт, а не целое в 4 байта или длинное целое в 8 байт!!
т.е. при сохранении в поток структуры, надо будет писать не outstrem.Write(data,SizeOf(TTestRecord))
а для каждого поля структуры отдельно
outstream.Write(data.id,sizeof(TTestRecord.id));
outstream.Write(data.data,sizeof(TTestRecord.data));
?? так конечно можно, но тогда какой смысл в структуре!? тогда изначально все хранить отдельно..... :shock:

Как быть?? как записать данные структуры, так чтобы они записались в том количестве, которое как бы подразумевает определение типа, а не поведение компилятора?
и соответственно как их тогда обратно прочитать в структуру?

Добавлено спустя 15 минут 30 секунд:
Код: Выделить всё
     TTestRecord = record
        id:Byte;
        case boolean of
         0 : (Buff:Array[1..5] of byte);
         1 : (Data:ShortInt);
      end;

при таком определении sizeOf выдает 6
и это правильно, но тут же
Код: Выделить всё
     TTestRecord = record
        id:Byte;
        case boolean of
         0 : (Buff:Array[1..5] of byte);
         1 : (Data:Pointer);
      end;

лови размер структуры = 16 !!!

ничего не понимаю....
как быть уверенным в размерах выдаваемых sizeof и собственно тем что задано в описании типа?

Добавлено спустя 26 минут 41 секунду:
дальнейшие изыскания ставят в тупик еще больше
Код: Выделить всё
   TTestShortArray = array of ShortInt;
   TTestIntegerArray = array of Integer;
   TTestLongIntArray = array of LongInt;
   TTestInt64Array = array of Int64; 
....
var
     p:Pointer;
Begin
   GetMem(p,1024);

   Memo1.Lines.Append(IntToStr(SizeOf(TTestShortArray(p)[0])));
   Memo1.Lines.Append(IntToStr(SizeOf(TTestIntegerArray(p)[0])));
   Memo1.Lines.Append(IntToStr(SizeOf(TTestLongIntArray(p)[0])));
   Memo1.Lines.Append(IntToStr(SizeOf(TTestInt64Array(p)[0])));


Выдаст такую вот инфу:
1
4
4
8

т.е.
ShortInt стал = byte
Integer стал = LongInt
остальные вроде ожидаемо:
LongInt = LongInt
Int64 = Int64

Добавлено спустя 5 минут 58 секунд:
попробовал для разных ОС, для Линукс и Выньдовс - результаты одинаковы, т.е. хоть в чем-то проблемы нет :)
при компиляции в другой ОСь, результат идентичен :)

Добавлено спустя 7 минут 17 секунд:
Код: Выделить всё
  TTestShortArray(p)[0]:=256;
  Memo1.lines.Append(IntToStr(TTestShortArray(p)[0]));

выдаст 0 - что по размеру SizeOf - ожидаемо
и варнинг при комплияции unit1.pas(50,26) Warning: range check error while evaluating constants (256 must be between -128 and 127)
как так-то? почему shortInt 2 байта - стал byte ??
ssnakess
новенький
 
Сообщения: 47
Зарегистрирован: 24.09.2011 23:08:55

Re: SizeOf для структур

Сообщение Дож » 04.09.2023 07:19:12

По умолчанию поля выравниваются для оптимизации скорости. Чтобы выравнять их для оптимизации по памяти или для записи в файл, нужно писать "packed record" вместо "record".

Free Pascal Reference guide, 3.3 Structured Types: https://www.freepascal.org/docs-html/re ... #QQ2-39-65

Также про выравнивание полей полезно знать, что если нужно выравнять их также как в Си (например, при подключении Сишной динамической библиотеки), нужно указать директиву {$PACKRECORDS C} и объявлять запись без packed: https://www.freepascal.org/docs-html/pr ... 60001.2.60
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

Re: SizeOf для структур

Сообщение ssnakess » 04.09.2023 11:05:03

Дож писал(а):По умолчанию поля выравниваются для оптимизации скорости. Чтобы выравнять их для оптимизации по памяти или для записи в файл, нужно писать "packed record" вместо "record".

:) волшебное слово packed для sizeOf решило проблему

Но как быть с этим?
Код: Выделить всё
TTestShortArray = array of ShortInt;
....
  TTestShortArray(p)[0]:=256;
  Memo1.lines.Append(IntToStr(TTestShortArray(p)[0]));

и Warning: range check error while evaluating constants (256 must be between -128 and 127)

куда компилятор дел ShortInt? Почему он его преобразовал в массив byte?
ssnakess
новенький
 
Сообщения: 47
Зарегистрирован: 24.09.2011 23:08:55

Re: SizeOf для структур

Сообщение Дож » 04.09.2023 11:55:56

TTestShortArray - это тип динамического массива, его внутреннее устройство на усмотрение компилятора. Каст TTestShortArray(p) от переменной p, которая не является динамическим массивом, -- это Undefined Behavior. Вместо этого с учётом того как вы используете этот тип правильнее объявить TTestShortArray = ^ShortInt;.

ShortInt ничем не становился, он всегда имел размер 1 байт и принимает значения в диапазоне -128..127: https://www.freepascal.org/docs-html/ref/refsu4.html
Разумеется, если попытаться записать 256 в ShortInt, то это стригерит range check error.

Размер Integer зависит от режима компиляции. В FPC и TP режимах он 2 байта, в OBJFPC и DELPHI -- 4. Да, Integer=LongInt в некоторых режимах.
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47


Вернуться в Обучение Free Pascal

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 12

Рейтинг@Mail.ru