Конференция "Основная" » Насколько адекватен SizeOf
 
  • Sha © (05.06.08 16:25) [0]
    Моя Delphi7 выводит 1 2 4 8 16 16 16 16 в качестве размеров структур, имеющих размер 1, 2, 4, 8, 9, 10, 12, 16 байт.
    Также замечено неадекватное поведение и для структур большего размера.

    Интересны результаты для других версий Delphi.

    Тестилось на этом коде

    type

     t1 = record
     b: byte;
     end;

     t2 = record
     w: word;
     end;

     t4 = record
     d: dword;
     end;

     t8 = record
     i: int64;
     end;

     t9 = record
     i: int64;
     b: byte;
     end;

     t10 = record
     i: int64;
     w: word;
     end;

     t12 = record
     i: int64;
     d: dword;
     end;

     t16 = record
     i: int64;
     i2: int64;
     end;

    procedure TForm1.FormCreate(Sender: TObject);
    begin
     Edit1.Text:=Format('%d %d %d %d %d %d %d %d',
     [SizeOf(t1), SizeOf(t2), SizeOf(t4), SizeOf(t8),
      SizeOf(t9), SizeOf(t10), SizeOf(t12), SizeOf(t16)]);
    end;

  • Palladin © (05.06.08 16:28) [1]
    с месяца два я распинался уже в "прочее" про выравниванивание полей в структурах... поди уже в архиве...


    > Также замечено неадекватное поведение и для структур большего
    > размера.

    оно вполне адекватное... приводи, обосную :)
  • Sha © (05.06.08 16:30) [2]
    > Palladin ©   (05.06.08 16:28) [1]

    я не спрашивал про выравнивание
  • Palladin © (05.06.08 16:31) [3]

    > Sha ©   (05.06.08 16:30) [2]

    а размер записи напрямую зависит от выравнивания
  • Palladin © (05.06.08 16:37) [4]
    а так же от расположения полей

    Type
    TRec1=Record
     a:Int64;
     b:Byte;
     c:Integer;
     d:Byte;
    End;

    TRec2=Record
     a:Int64;
     b:Byte;
     d:Byte;
     c:Integer;
    End;



    абсолютно разные SizeOf, если немного поэкспериментировать, можно выявить как компилятор упаковывает поля записи и как влияет на упаковку директива {$A}
  • Sha © (05.06.08 16:39) [5]
    > Palladin ©   (05.06.08 16:31) [3]

    Про выравнивание все ясно, и что размер записи зависит от выранивания тоже ясно.
    Только неясно, почему t1 имеет размер 1 байт, а t5 - 8.
    Это может примести к ошибкам в операторах типа

    Move(r1,abc,SizeOf(t1)); //тут скопируется 1 байт
    Move(r5,abc,SizeOf(t5)); //тут скопируется 8 байт, а не 5, как ожидаю я

  • Плохиш © (05.06.08 16:41) [6]

    > Sha ©   (05.06.08 16:25)  
    > Моя Delphi7 выводит 1 2 4 8 16 16 16 16 в качестве размеров
    > структур, имеющих размер 1, 2, 4, 8, 9, 10, 12, 16 байт.

    Пиши
    packed record

    и получишь желаемые цифры.
  • Плохиш © (05.06.08 16:43) [7]

    > Про выравнивание все ясно, и что размер записи зависит от
    > выранивания тоже ясно.
    > Только неясно, почему t1 имеет размер 1 байт, а t5 - 8.

    Хм, решил мне телепатор сломать, не выйдет...
  • Palladin © (05.06.08 16:46) [8]
    1. по видимому, компилятор воспринимает запись из одного поля, как просто тип этого поля
    2. move вообще опасно применять к не packed записям, программист всегда должен иметь ввиду, что размер записи может не совпадать, не то чтобы с  суммой размеров полей, но и быть разным даже в зависимости от директив и настроек компилятора.
  • Anatoly Podgoretsky © (05.06.08 16:48) [9]
    > Sha  (05.06.2008 16:25:00)  [0]

    В чем неадекватность, и наверно твое представление не совпадает с представлением компилятора, а понять его не всегда легко.
  • Sha © (05.06.08 16:49) [10]
    > Плохиш ©   (05.06.08 16:43) [7]

    С чего все началось. Было замечено , что тип t44 независио от packed, но в зависимости от расположения звезд на небе имеет размер 44 или 48 байт

     t44 = record
     i1: int64;
     i2: int64;
     i3: int64;
     i4: int64;
     d1: dword;
     d2: dword;
     d3: dword;
     end;

  • Anatoly Podgoretsky © (05.06.08 16:49) [11]
    > Sha  (05.06.2008 16:25:00)  [0]

    Кстати если тебе нужна адекватность, то используй слово Packed
  • Sha © (05.06.08 16:51) [12]
    > Palladin ©   (05.06.08 16:46) [8]
    > move вообще опасно применять к не packed записям

    и как показывает пост [10] и к Packed тоже
  • Sha © (05.06.08 16:52) [13]
    > Anatoly Podgoretsky ©   (05.06.08 16:49) [11]

    Тут не стоит вопрос как обойти проблему и получить адекватность,
    это я знаю.

    Вопрос в том, есть этот глюк в новых версиях Дельфи
  • Palladin © (05.06.08 16:53) [14]

    > Sha ©   (05.06.08 16:49) [10]

    ну, я думаю это что то не реальное. у меня стабильно у packed 44. как воспроизвести?
  • Anatoly Podgoretsky © (05.06.08 16:55) [15]
    > Sha  (05.06.2008 16:30:02)  [2]

    А как ты это представляешь, выравнивание без изменения размера?
  • Sha © (05.06.08 17:05) [16]
    > Palladin ©   (05.06.08 16:53) [14]
    > ну, я думаю это что то не реальное. у меня стабильно у packed 44. как воспроизвести?

    Ты под другими звездами :)

    У нас проект большой.
    Похоже дело в том, что описание типа и
    егo использование в разных модулях.

    Последовательность дейсвий такая.
    Убираем packed, билдим проект, получаем 48
    Ставим packed, компилируем, получаем 48
    Билдим, получаем 44
  • Sha © (05.06.08 17:06) [17]
    > Anatoly Podgoretsky ©   (05.06.08 16:55) [15]
    > А как ты это представляешь, выравнивание без изменения размера?

    Не понял
  • Anatoly Podgoretsky © (05.06.08 17:07) [18]
    > Sha  (05.06.2008 16:52:13)  [13]

    Не знаю, никогда не заморачивался этой проблемой.
    Но Packed всегда работал ожидаемо.
  • Sha © (05.06.08 17:12) [19]
    > Anatoly Podgoretsky ©   (05.06.08 17:07) [18]
    > Мы тоже всегда используем packed. Он работает ожидаемо. Неожиданно работает SizeOf :)

    Еще раз повторюсь, не надо советов, что мне надо сделать.

    Просьба, скомпилировать исходный пример и запустить под другими версиями Дельфи.
  • Sha © (05.06.08 17:13) [20]
    Сорь, не так цитатки поставил

    > Anatoly Podgoretsky ©   (05.06.08 17:07) [18]
    Мы тоже всегда используем packed. Он работает ожидаемо. Неожиданно работает SizeOf :)

    Еще раз повторюсь, не надо советов, что мне надо сделать.

    Просьба, скомпилировать исходный пример и запустить под другими версиями Дельфи.
  • oxffff © (05.06.08 17:15) [21]

    > Sha ©   (05.06.08 16:25)  


    Можете как то доступно объянить в что вас конкретно не устраивает. Логика выравнивания?
    Вы хотите сказать что компилятор самопроизвольно меняет размер записи и факт того , что две идентичных записи не смогут корректно взаимодейстовать скомпилированных раздельно если звезда моргнет?
  • Sha © (05.06.08 17:17) [22]
    Исправления в пост [5]

    для
    > Palladin ©   (05.06.08 16:31) [3]
    >Плохиш ©   (05.06.08 16:43) [7]

    Про выравнивание все ясно, и что размер записи зависит от выранивания тоже ясно.
    Только неясно, почему t1 имеет размер 1 байт, а t9- 16.
    Это может примести к ошибкам в операторах типа

    Move(r1,abc,SizeOf(t1)); //тут скопируется 1 байт
    Move(r9,abc,SizeOf(t9)); //тут скопируется 16 байт, а не 9, как ожидаю я
  • Kolan © (05.06.08 17:17) [23]

    > Интересны результаты для других версий Delphi.

    Для каких других?
  • Игорь Шевченко © (05.06.08 17:18) [24]
    1 2 4 8 16 16 16 16

    Turbo Delphi 2006
  • Kolan © (05.06.08 17:20) [25]
    RAD 2007
    1 2 4 8 16 16 16 16

    BDS 2006
    1 2 4 8 16 16 16 16
  • Sha © (05.06.08 17:20) [26]
    > oxffff ©   (05.06.08 17:15) [21]
    Меня не устраивает, что я должен искать обходные пути для копирования типа t44, даже если он packed

    Move(r44,abc,SizeOf(t44)); //тут скопируется 48 байт, а не 44, как ожидаю я

    Но не этом вопрос, а про другие весии Дельфи
  • Sha © (05.06.08 17:22) [27]
    > Игорь Шевченко ©   (05.06.08 17:18) [24]
    > Kolan ©   (05.06.08 17:20) [25]

    Понятно, спасибо, будем иметь ввиду
  • Sha © (05.06.08 17:23) [28]
    > Sha ©   (05.06.08 17:20) [26]
    > oxffff ©   (05.06.08 17:15) [21]

    Причем может скопироваться и 44,в зависимости от истории исправлений см [16]
  • Плохиш © (05.06.08 18:01) [29]

    > Sha ©   (05.06.08 17:05) [16]


    > Последовательность дейсвий такая.
    > Убираем packed, билдим проект, получаем 48
    > Ставим packed, компилируем, получаем 48
    > Билдим, получаем 44


    Ну и? Всё описано в документации.
    1. SizeOf для типа - константа, которая будет вставлена при компиляции в dcu.
    2. Компиляция затрагивает только те модули, исходник которых был изменён, проверяется, кстати, по дате. Соответственно при сборке будут взяты dcu со старым значением SizeOf.
    3. Build перекомпилирует все модули, соответственно получаем новые значения размеров.

    > Sha ©   (05.06.08 17:17) [22]
    > Move(r1,abc,SizeOf(t1)); //тут скопируется 1 байт
    > Move(r9,abc,SizeOf(t9)); //тут скопируется 16 байт, а не
    > 9, как ожидаю я

    Хм, а почему ты ожидаешь не то, что описано в справке?

    If two fields share a common type specification, they are packed even if the declaration does not include the packed modifier and the record type is not declared in the {$A-} state. Thus, for example, given the following declaration
    type
     TMyRecord = record
       A, B: Extended;  
       C: Extended;
     end;
    A and B are packed (aligned on byte boundaries) because they share the same type specification. The compiler pads the structure with unused bytes to ensure that C appears on a quadword boundary.

  • Palladin © (05.06.08 18:16) [30]

    > проверяется, кстати, по дате.

    этот нюанс, кстати, тоже все время ввиду иметь нужно... решение, мягко говоря, ненадежное и приводит иногда к эффекту, тех самых, космических лучей :)...
  • Sha © (05.06.08 20:04) [31]
    > Плохиш ©   (05.06.08 18:01) [29]
    > 2. Компиляция затрагивает только те модули, исходник которых был изменён

    Это неверно.
    Пример.

    Добавляем в проект модуль

    unit SizeOfU2;

    interface

    type
     TMy1= integer;
     TMy2= record
       pref: int64;
       i2: integer;
       end;

    implementation

    end.



    и кнопку

    uses
     SizeOfU2;

    procedure TForm1.Button1Click(Sender: TObject);
    var
     i1: TMy1;
     i2: TMy2;
    begin
    Edit1.Text:=Format('%d %d',
    [SizeOf(TMy1), SizeOf(TMy2)]);
    end;




    компилируем, пускаем, жмем, получаем размеры 4,16
    вносим изменения только в добавленный модуль   TMy1= int64;
    компилируем, пускаем, жмем, получаем размеры 8,16
    вносим изменения только в добавленный модуль   TMy2= packed record
    компилируем, пускаем, жмем, получаем размеры 8,16
    билдим, пускаем, жмем, получаем размеры 8,12

    Ситуация усугубляется, если имеется группа проектов.

    > Хм, а почему ты ожидаешь не то, что описано в справке?

    А где в справке написано, что размер не packed cтруктуры не равен смещению последнего байта данных+1? Причем только в том случае не равен, когда она содержит более одного поля.

    > If two fields share a common type specification,

    А это ты к чему? У меня такого нет.

    P.S.
    Ну и еще раз. У меня нет проблем. Я знаю как все это обойти. Мне просто хотелось более адекватного поведения компилятора. Надеялся, что в новых версиях эти грабли отсутствуют. Видно, придется и дальше использовать packed, а чтоб он не ломал выравнивание вводить резервные поля, после каждого изменения packed/не packed перебилдивать, и чтоб уж совсем параноидально застраховаться от ошибочного убирания packed в будущем дополнять запись какой-нить фигней до размера, кратного 16.
  • Sha © (05.06.08 21:09) [32]
    В проекте используются вложенные структуры данных.
    Я написал небольшой тест для них:

    type
     T1n= record
       a: byte;
       end;
     T1p= packed record
       a: byte;
       end;
     T2n= record
       a: integer;
       b: byte;
       end;
     T2p= packed record
       a: integer;
       b: byte;
       end;

     T11nn= packed record
       a: T1n;
       b: T1n;
       end;
     T11np= packed record
       a: T1n;
       b: T1p;
       end;
     T11pn= packed record
       a: T1p;
       b: T1n;
       end;
     T11pp= packed record
       a: T1p;
       b: T1p;
       end;

     T21nn= packed record
       a: T2n;
       b: T1n;
       end;
     T21np= packed record
       a: T2n;
       b: T1p;
       end;
     T21pn= packed record
       a: T2p;
       b: T1n;
       end;
     T21pp= packed record
       a: T2p;
       b: T1p;
       end;

     T22nn= packed record
       a: T2n;
       b: T2n;
       end;
     T22np= packed record
       a: T2n;
       b: T2p;
       end;
     T22pn= packed record
       a: T2p;
       b: T2n;
       end;
     T22pp= packed record
       a: T2p;
       b: T2p;
       end;

     N11nn= record
       a: T1n;
       b: T1n;
       end;
     N11np= record
       a: T1n;
       b: T1p;
       end;
     N11pn= record
       a: T1p;
       b: T1n;
       end;
     N11pp= record
       a: T1p;
       b: T1p;
       end;

     N21nn= record
       a: T2n;
       b: T1n;
       end;
     N21np= record
       a: T2n;
       b: T1p;
       end;
     N21pn= record
       a: T2p;
       b: T1n;
       end;
     N21pp= record
       a: T2p;
       b: T1p;
       end;

     N22nn= record
       a: T2n;
       b: T2n;
       end;
     N22np= record
       a: T2n;
       b: T2p;
       end;
     N22pn= record
       a: T2p;
       b: T2n;
       end;
     N22pp= record
       a: T2p;
       b: T2p;
       end;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
    Memo1.Lines.Add(Format('T1n=%d T1p=%d',
    [SizeOf(T1n), SizeOf(T1p)]));

    Memo1.Lines.Add(Format('T2n=%d T2p=%d',
    [SizeOf(T2n), SizeOf(T2p)]));

    Memo1.Lines.Add(Format('T11nn=%d T11np=%d T11pn=%d T11pp=%d',
    [SizeOf(T11nn), SizeOf(T11np), SizeOf(T11pn), SizeOf(T11pp)]));

    Memo1.Lines.Add(Format('T21nn=%d T21np=%d T21pn=%d T21pp=%d',
    [SizeOf(T21nn), SizeOf(T21np), SizeOf(T21pn), SizeOf(T21pp)]));

    Memo1.Lines.Add(Format('T22nn=%d T22np=%d T22pn=%d T22pp=%d',
    [SizeOf(T22nn), SizeOf(T22np), SizeOf(T22pn), SizeOf(T22pp)]));

    Memo1.Lines.Add(Format('N11nn=%d N11np=%d N11pn=%d N11pp=%d',
    [SizeOf(N11nn), SizeOf(N11np), SizeOf(N11pn), SizeOf(N11pp)]));

    Memo1.Lines.Add(Format('N21nn=%d N21np=%d N21pn=%d N21pp=%d',
    [SizeOf(N21nn), SizeOf(N21np), SizeOf(N21pn), SizeOf(N21pp)]));

    Memo1.Lines.Add(Format('N22nn=%d N22np=%d N22pn=%d N22pp=%d',
    [SizeOf(N22nn), SizeOf(N22np), SizeOf(N22pn), SizeOf(N22pp)]));
    end;


    Получен результат:

    T1n=1 T1p=1
    T2n=8 T2p=5
    T11nn=2 T11np=2 T11pn=2 T11pp=2
    T21nn=9 T21np=9 T21pn=6 T21pp=6
    T22nn=16 T22np=13 T22pn=13 T22pp=10
    N11nn=2 N11np=2 N11pn=2 N11pp=2
    N21nn=12 N21np=12 N21pn=6 N21pp=6
    N22nn=16 N22np=16 N22pn=16 N22pp=10


    Мне не удалось двумя словами описать правила, которыми руководствуется компилятор.
    Может, кто-нибудь сможет? :)
  • Anatoly Podgoretsky © (05.06.08 21:19) [33]
    > Sha  (05.06.2008 20:04:31)  [31]

    Ты ждешь от компилятора того, что он уже давно потерял, давно не адекватен, а выравнивание и размер загадка для многих, мало кто в состоянии без проверки сказать точно какой размер будет у структуры.

    Раз знаешь как обойти, то плюнь и отойди.
  • Anatoly Podgoretsky © (05.06.08 21:49) [34]
    > Sha  (05.06.2008 21:09:32)  [32]

    Ой это вообще делает ситуацию неопределенной.
  • Sha © (05.06.08 22:16) [35]
    > Anatoly Podgoretsky ©   (05.06.08 21:49) [34]

    Да не, нормально, если все делать, как в [31].
    Вот только контролировать - проблема, есть шанс не заметить не пакед структуру.
  • Anatoly Podgoretsky © (05.06.08 22:29) [36]
    > Sha  (05.06.2008 22:16:35)  [35]

    Согласен, но у меня проблем не возникало, может потому что я недопускаю неодназначных конструкций и не использую конструкции типа низкоуровневого Move и подобных. Вот когда коснется, вот тогда и буду разбираться.
  • просто так (05.06.08 22:39) [37]
    в d7 разбирался с выравниванием, сложного ниче небыло, работали сложные структуры без packed. позже пришлось вообще отказаться от выравнивания изза переезда на fpc
  • просто так (05.06.08 22:43) [38]
    про compile и build - проскакивают старые dcu, d7 и d2006 с этим ведут себя одинакого помоему
  • Плохиш © (05.06.08 23:00) [39]

    > Sha ©   (05.06.08 20:04) [31]
    > > Плохиш ©   (05.06.08 18:01) [29]


    > > If two fields share a common type specification,
    >
    > А это ты к чему? У меня такого нет.

    Вообщв-то, в следующих букавках приводиться пример, почему запись T9 имеет размер 16 байт, а неожидаемый, почему-то, тобой 9 байт. Конечно, борланд поступил нехорошо не указав в примере все возможные комбинации записей.

    PS. Хотите верить в чудеса, так пожалуйста, никто не запрещает...
  • Sha © (05.06.08 23:12) [40]
    > просто так   (05.06.08 22:39) [37]
    > в d7 разбирался с выравниванием, сложного ниче небыло

    а кому тут сложно?
    нам мозги не заморочить даже примером из [32]

    > Плохиш ©   (05.06.08 23:00) [39]
    > Вообщв-то, в следующих букавках приводиться пример, почему запись T9 имеет размер 16 байт

    Нет, не приводится. Там пишут про следующее поле C:
    > The compiler pads the structure with unused bytes to ensure that C appears on a quadword boundary.
    а в моем примере нету следующего поля (3-его)

    >  Хотите верить в чудеса,
    а это зачем?
  • Плохиш © (05.06.08 23:19) [41]

    > Нет, не приводится. Там пишут про следующее поле C:
    > > The compiler pads the structure with unused bytes to ensure
    > that C appears on a quadword boundary.
    > а в моем примере нету следующего поля (3-его)

    В твоём примере вместо этих 2х полей, одно размером 8 байт и на столько же сдвинуто следующее поле однобайтное, т.е. выравнено по восьмому байту. Или я не прав?
  • Sha © (05.06.08 23:27) [42]
    > Плохиш ©   (05.06.08 23:19) [41]

    1. Борланд нигде не говорит, что размер неупакованной записи, имеющей более одного поля, округляется вверх до заданного при компиляции выравнивания.
    2. При перекомпиляции проекта в после изменения атрибута packed в каком-либо модуле Борланд забывает перекомпилировать зависимые от него модули.
  • Плохиш © (05.06.08 23:59) [43]

    > Sha ©   (05.06.08 23:27) [42]


    > 1. Борланд нигде не говорит, что размер неупакованной записи,
    >  имеющей более одного поля, округляется вверх до заданного
    > при компиляции выравнивания.

    Я этой фразы честно сказать не понял, а в справке по bds2006 для Record Types написано, что выравнивание в записях производиться по
    the largest alignment of the fields in the record



    > 2. При перекомпиляции проекта в после изменения атрибута
    > packed в каком-либо модуле Борланд забывает перекомпилировать
    > зависимые от него модули.

    Значит эти модули не попадают под условия перекомпиляции, которые описаны в справке, в частности к D7.
  • Anatoly Podgoretsky © (06.06.08 00:03) [44]
    > Sha  (05.06.2008 23:27:42)  [42]

    Ранее вроде так и былоо, но потом они стали мудрить с выравниваниями и возможно с размерами, что упростить себе жизнь.
  • Sha © (06.06.08 00:45) [45]
    > Плохиш ©   (05.06.08 23:59) [43]

    > Я этой фразы честно сказать не понял, а в справке по bds2006 для Record
    > Types написано, что выравнивание в записях производиться по the largest
    > alignment of the fields in the record

    Выравнивание и размер - разные вещи. Выравнивание говорит о том, откуда пое начинается, размер - где запись заканчивается. Борланд много (но недостаточно - например, не говорит о выравнивании вложенных записей)говорит о выравнивании, но мало о размере записи. В моем примере
    t9 = record
    i: int64;
    b: byte;
    end;


    понятно, что последний байт данных находится по смещению +8 от начала записи. Логично предположить, что размер записи равен 9. Но это не так по мнению Борланда, он считает, что размер равен 16, т.е. произошло округление вверх до нужной кратности. Замечательно. Пусть будет так.
    смотрим на другой пример.
    t1 = record
    b: byte;
    end;


    Логично предположить, что в данном случае Борланд поступит аналогично и увеличит размер записи с 1 до 8. Но он этого не делает.
    Ага, думаем мы. Наверно это из-за того, что поле одно. Но смотрим дальше.
    tt1 = record
    b: byte;
    b2: byte;
    end;


    Тут размер равен 2.
    А тут 8 и 16:
    tt2 = record
    b: integer;
    b2: byte;
    end;



    tt2 = record
    b: integer;
    b2: byte;
    end;


    Т.е. похоже размер тоже округляется до
    the largest alignment of the fields in the record



    и вроде бы пример
    tt1 = record
    c: integer;
    b2: int64;
    c1: integer;
    end;



    (размер 24) подтверждает это.
    Следующий пример(тоже 24) опровергает:
    tt1 = record
    c: integer;
    b2: int64;
    c1: byte;
    c2: byte;
    end;



    В общем, ничего сложного :)

    > Значит эти модули не попадают под условия перекомпиляции, которые
    > описаны в справке, в частности к D7.

    Значит условия неверные, если зависимые модули не перекомпилируются.
  • Германн © (06.06.08 00:56) [46]

    > > Значит эти модули не попадают под условия перекомпиляции,
    >  которые
    > > описаны в справке, в частности к D7.
    >
    > Значит условия неверные, если зависимые модули не перекомпилируются.
    >
    >

    Кстати, лично меня больше беспокоило бы именно это обстоятельство.
  • Sha © (06.06.08 01:05) [47]
    > Sha ©   (06.06.08 00:45) [45]
    Поправка. Запутался в примерах.
    Последний пример ничего не опровергает.

    > Т.е. похоже размер тоже округляется до the largest alignment of the fields in the record.
    Это, вроде, верно для неупакованных записей.
  • Sha © (06.06.08 01:15) [48]
    > Sha ©   (06.06.08 01:05) [47]
    Верно, но не всегда
    Например,
    tt1 = record
    b2: int64;
    c1: byte;
    w: integer;
    c2: byte;
    end;


    имеет размер 20 при {$Align 4} и 24 при {$Align 8}

    Т.е. округление производится до largest alignment of the fields in the record,
    но не более заданного в {$Align}.
    Вроде так.
  • Плохиш © (06.06.08 10:31) [49]

    > Sha ©   (06.06.08 00:45) [45]
    > > Плохиш ©   (05.06.08 23:59) [43]
    >
    > > Я этой фразы честно сказать не понял, а в справке по bds2006
    > для Record
    > > Types написано, что выравнивание в записях производиться
    > по the largest
    > > alignment of the fields in the record
    >
    > Выравнивание и размер - разные вещи. Выравнивание говорит
    > о том, откуда пое начинается, размер - где запись заканчивается.
    >  Борланд много (но недостаточно - например, не говорит о
    > выравнивании вложенных записей)говорит о выравнивании, но
    > мало о размере записи. В моем примере
    > t9 = record
    > i: int64;
    > b: byte;
    > end;
    > понятно, что последний байт данных находится по смещению
    > +8
    от начала записи. Логично предположить, что размер записи
    > равен

    Т.е. даже справку прочитать не модно, вообще-то там говорится, что для b будет выделено столько же байт, что и для i, храниться b будет в последнем байте этого выделения, а предыдущие байты не используются, т.е. последний байт находится по смещению +15 от начала записи.

    PS. Когда-то давно, вроде даже, борланд схематично показывали выравнивание и распределение неупакованных записей.

    PPS. Ветка как-то превратилась в переливание из пустого в порожнее :-(
  • Evgeny V © (06.06.08 10:38) [50]

    > Sha ©   (05.06.08 17:05) [16]


    > Sha ©   (05.06.08 17:12) [19]


    Если еще интересны результаты -
    t44
    D6
    В проекте в опциях компилятора стоит Record Field Aligmnet - 8 -> размер структуры всегда 48. Меняем на 4, перекомпилируем -> размер структуры  48, перестраиваем(build) ->размер структуры  44
    Видно, что размер структуры выранвнивается на число равное или большее размеру структуры и кратное указанному в параметре Record Field Alignment, и что перекомпиляция не видит изменение этого параметра в проекте...
  • Sha © (06.06.08 10:55) [51]
    > Evgeny V ©   (06.06.08 10:38) [50]

    Таким образом, компилятор делает примерно следующее.
    Для каждого типа данных он знает его максимальные претензии на выравнивание
    (например, для целых типов это их размер). Кроме того, у себя в голове он
    держит величину выравнивания, заданную в {$Align}, и еще одну переменную,
    которая для упакованных записей равна 1, а для неупакованных совпадает {$Align}.
    Затем для каждого типа данных компилятор вычисляет минимальные претензии
    типа на выравнивание. Это значение равно минимальному из трех, приведенных выше.
    В записи поля выравниваются в соответствии с минимальными претензиями на
    выравнивание их типов. Размер записи вычисляется как смещение последнего байта
    данных плюс 1 и затем округляется в большую сторону до максимального значения
    из всех минимальных претензий на выравнивание.
    Этот алгоритм применим и к вложенным записям.

    Поэтому, например, тип t9
    t9 = record
     i: int64;
     b: byte;
     end;


    будет иметь длину 9, 10, 12 или 16 в зависимости от значения {$Align},
    равного 1, 2, 4 или 8.

    К всему этому можно было подойти с другой стороны. Для перемешения к следующему
    элементу в массиве записей нам хотелось бы просто увеличивать указатель на размер
    записи. Приведенное выше правило в совокупности с правилами выравнивания записей
    как раз и обеспечивает такую возможность. На мой взгляд, этим и объясняется
    кажущаяся неадекватность компилятора.

    Но баг с неперекомпиляцией, конечно, остается багом.
  • Anatoly Podgoretsky © (06.06.08 11:51) [52]
    > Sha  (06.06.2008 10:55:51)  [51]

    > К всему этому можно было подойти с другой стороны. Для перемешения к следующему
    элементу в массиве записей нам хотелось бы просто увеличивать указатель на размер
    записи. Приведенное выше правило в совокупности с правилами выравнивания записей
    как раз и обеспечивает такую возможность. На мой взгляд, этим и объясняется
    кажущаяся неадекватность компилятора.

    Это не причем, если перемещение делаешь с помощью SizeOf то без разницы упакованое или нет, истинный размер. А вот то что не перекомпилирует плохо, но это не может привести к ошибке, поскольку если файл с определением изменился, то все зависимые изменятся тоже. Проблема может возникнуть только при передаче данных, но она точно также возникнет и при полной перекомпиляции.
    Но можно отметить, что Борланд постоянно играется с выравниванием и его поведением и в тоже время не доводит это дело до конца нет выравнивания на границу 16 байт, а уже актуально и 32 байта.
    Документация тоже отстает от реальности.
    Пока они не сделали управление выравниванием, у них была одназначность и повторяемость.

    > Но баг с неперекомпиляцией, конечно, остается багом.

    Не уверен, хотя если это делается без изменения файла от которого зависят остальные, то только тогда баг. Ну так делать билд, поскольку тогда это будет касаться не только этой настройки, но и многих других.

    Перекомпилируются ли зависимые модули, если в модуле с определением добавить и удалить пробел?
    Перекомпилируются ли зависимые модули, если в модуле с определением добавить изменить переключатель А?
    Перекомпилируются ли зависимые модули, если тоже самое сделать в настройках проекта?
  • Sha © (06.06.08 11:54) [53]
    > Плохиш ©   (06.06.08 10:31) [49]
    > Т.е. даже справку прочитать не модно, вообще-то там говорится, что для
    > b будет выделено столько же байт, что и для i, храниться b будет в
    > последнем байте этого выделения, а предыдущие байты не используются,
    > т.е. последний байт находится по смещению +15 от начала записи.

    Неверно.

    Попробуй выполнить это, убедишься, что ты не прав.

    procedure TForm1.Button1Click(Sender: TObject);
    var
     t: t9;
    begin
     ShowMessage(IntToStr(pchar(@t.b)-pchar(@t.i)));
    end;



    > PPS. Ветка как-то превратилась в переливание из пустого в порожнее :-(

    У тебя есть право не читать :)
  • Sha © (06.06.08 12:00) [54]
    > Anatoly Podgoretsky ©   (06.06.08 11:51) [52]
    Зависимые модули не перекомпилируются, если в модуле с определением добавить или удалить packed. Этого для бага достаточно.
  • Плохиш © (06.06.08 13:42) [55]

    > Sha ©   (06.06.08 11:54) [53]
    > > Плохиш ©   (06.06.08 10:31) [49]
    > > Т.е. даже справку прочитать не модно, вообще-то там говорится,
    >  что для
    > > b будет выделено столько же байт, что и для i, храниться
    > b будет в
    > > последнем байте этого выделения, а предыдущие байты не
    > используются,
    > > т.е. последний байт находится по смещению +15 от начала
    > записи.
    >
    > Неверно.

    Действительно неправ, как-то вылетело, что младший байт храниться по младшему адресу. Но предположение о размере записи всё-равно нелогично, так как для последнего поля выделяется один байт, только в одном случае, когда выравнивание установлено в 1 {A1}.

    > Sha ©   (06.06.08 12:00) [54]
    > Зависимые модули не перекомпилируются, если в модуле с определением
    > добавить или удалить packed. Этого для бага достаточно.

    Судя по справке к D7, это не баг, а фича, т.к. описано. А вот для BDS2006 это бага, там в справке Compiling Applications третим пунктом стоит, что при запуске на выполнение, перекомпилируются также и все зависимые модули.
  • Anatoly Podgoretsky © (06.06.08 13:56) [56]
    > Sha  (06.06.2008 12:00:54)  [54]

    Тогда согласен, но это странно, ведь перекомпиляция основана на факте изменения даты, а не содержимого.
    Если это так, то это определенно баг, но он должен касаться любых изменений.
    А вот настройки в среде другое дело, но я привык делать Build при изменение настроек.
  • Sha © (06.06.08 14:03) [57]
    > Плохиш ©   (06.06.08 13:42) [55]
    > для последнего поля выделяется один байт, только в одном случае, когда выравнивание установлено в 1 {A1}.

    Здесь, конечно, дело вкуса.

    Тебе почему-то удобней думать, что последнее поле, в котором лежит однобайтовая переменная, занимает 8 байт, несмотря на то, что компилятор с ним оперирует именно как с одним байтом во всех операциях (арифметика, логика, пересылка). Твое право.

    Я определяю размер поля по тому, как с ним работает компилятор. Так моим мозгам удобнее.
  • Sha © (06.06.08 14:05) [58]
    > Anatoly Podgoretsky ©   (06.06.08 13:56) [56]
    > но он должен касаться любых изменений...

    Любых не касается.
    Например, если изменить тип поля, все компилирутся как надо.
  • Anatoly Podgoretsky © (06.06.08 14:41) [59]
    > Sha  (06.06.2008 14:05:58)  [58]

    Добавление Packed это по сути и есть изменение типа поля.
    Но я уже писал, что перекомпиляция связаных модулей не зависит от содержимого, а только от дат, основано на make.
    А по твоим словам ты же именно модуль меняешь
  • Sha © (06.06.08 14:52) [60]
    > Anatoly Podgoretsky ©   (06.06.08 14:41) [59]

    Это не я писал, хотя это верно :)
    Последовательность действий по воспроизведению бага описана [16].
    Тут суть в том, что модули на диске не перезаписываются и дата у них не меняется.
    Изменения делаются непосредственно в среде Дельфи.
    И некоторые из них Дельфи учитывает в зависимых модулях, а некоторые - нет.
  • Anatoly Podgoretsky © (06.06.08 15:09) [61]
    > Sha  (06.06.2008 14:52:00)  [60]

    Я уже матюгался? Нет, ну тогда матюгаюсь, Борланд пошел по попсовому пути, набросать много не нужных функций, и попутно теряя надежность компилятора, делая всякие колокольчики. А переход к ebarcader может ситуацию еще больше ухудшить. Все лучшие кадры подарили или Микрософту или Ораклу и другим фирмам.
  • Плохиш © (06.06.08 15:15) [62]

    > Sha ©   (06.06.08 14:03) [57]
    > > Плохиш ©   (06.06.08 13:42) [55]
    > > для последнего поля выделяется один байт, только в одном
    > случае, когда выравнивание установлено в 1 {A1}.
    >
    > Здесь, конечно, дело вкуса.
    >
    > Тебе почему-то удобней думать, что последнее поле, в котором
    > лежит однобайтовая переменная, занимает 8 байт,

    Согласись, что понятия "занимает байт" и "распределено байт" несколько отличаются. И мне как-то удобней думать, что структуры данных занимают столько байт, как это описано в документации разработчиков компилятора.
  • Плохиш © (06.06.08 15:16) [63]

    > Anatoly Podgoretsky ©   (06.06.08 15:09) [61]

    +1 :-(
  • имя (06.06.08 15:23) [64]
    Удалено модератором
    Примечание: offtopic
  • Sha © (06.06.08 15:30) [65]
    Удалено модератором
    Примечание: offtopic
  • Anatoly Podgoretsky © (06.06.08 15:34) [66]
    Удалено модератором
    Примечание: offtopic
  • имя (06.06.08 15:40) [67]
    Удалено модератором
    Примечание: offtopic
  • Плохиш © (06.06.08 15:46) [68]
    Нифигасе, страсти накалились 8-O
  • Sha © (06.06.08 16:40) [69]
    > Плохиш ©   (06.06.08 15:15) [62]

    Вот пример, который прояснит мою позицию.
    Известно, что память в Д7 под строки выделяется двойными словами. И если длина строки кратна 4, то терминатор попадает в отдельный dword. Но никому ведь не приходит в голову говорить, что терминатор занимает или под него выделено двойное слово, потому что три лишних байта потребовались строке в целом, а не терминатору. Т.е. размер строки был округлен до 4 вверх.
    Так и случае с записями. Лишние байты не принадлежат последнему полю. На мой взгляд.
  • Anatoly Podgoretsky © (06.06.08 16:45) [70]
    Это понятно, но это психология, тут претензии только к Борланду, а есть ли при работе ошибка?
  • Palladin © (06.06.08 16:57) [71]

    > Лишние байты не принадлежат последнему полю.

    конечно не приналежат они "боксам" внутри записи принадлежат, а вот размеры "боксов" уже плавают в зависимости от самого большого типа и от директивы выравнивания

    интересный эксперимент
    {$A8}
    TMR1=Record
     a:Byte;
     // - щель 1b
     c:Word;
     d:Byte;
     // - щель 1b
     e:Word;
    End; // 8b

    TMR2=Record
     a:Byte;
     // 1b
     c:Word;
     // 2b
     d:Byte;
     // 3b
     e:Integer;
    End; // 12b

    хотя

    {$A2}
    TMR1=Record
     a:Byte;
     // - щель 1b
     c:Word;
     d:Byte;
     // - щель 1b
     e:Word;
    End; // 8b

    TMR2=Record
     a:Byte;
     // 1b
     c:Word;
     // 2b
     d:Byte;
     // 1b
     e:Integer;
    End; // 10b

  • Palladin © (06.06.08 17:07) [72]
    в последнем типе ошибся

    {$A2}
    TMR2=Record
    a:Byte;
    // 1b
    c:Word;
    d:Byte;
    // 1b
    e:Integer;
    End; // 10b

  • Palladin © (06.06.08 17:58) [73]
    так, еще раз и без косяков... :)

    {$A8}
    TMR1=Record
     a:Byte;
     "просвет" 1b
     c:Word;
     d:Byte;
     "просвет" 1b
     e:Word;
    End; 8b

    TMR2=Record
     a:Byte;
     "просвет" 1b
     c:Word;
     d:Byte;
     "просвет" 3b
     e:Integer;
    End; 12b

    {$A2}
    TMR1=Record
     a:Byte;
     "просвет" 1b
     c:Word;
     d:Byte;
     "просвет" 1b
     e:Word;
    End; 8b

    TMR2=Record
     a:Byte;
     "просвет" 1b
     c:Word;
     d:Byte;
     "просвет" 1b
     e:Integer;
    End; 10b

  • Sha © (06.06.08 18:32) [74]
    > Anatoly Podgoretsky ©   (06.06.08 16:45) [70]
    > ... а есть ли при работе ошибка?

    В [51] я попытался кратко изложить логику работы компилятора при выравнивании полей записи и определении размера записи.
    Более того, Борланд следует приведенному алгоритму и во вложенных структурах.
    Ошибок не обнаружено :)

    Там же я сделал предположение, зачем потребовался такой не совсем очевидный алгоритм определения размера записи.
    Здесь у Борланда все сходится идеально.
  • tesseract © (06.06.08 19:37) [75]

    > зачем потребовался такой не совсем очевидный алгоритм определения
    > размера записи.


    Может связано с оптимизацией работы кучи ?
  • Anatoly Podgoretsky © (07.06.08 01:18) [76]
    Я уже писал, для оптимизации компилятора и частично работы.
    Так писать проще, достаточно провести анализ только для первой переменной, остальные автоматическу получаются выровнеными.
  • KSergey © (07.06.08 09:42) [77]
    Может и не в тему
    http://forum.sources.ru/index.php?showtopic=110906

    Формально по ссылке наверное написано правильно, но, если честно, моему осознанию сильно мешает то, что автор не привел свое толкование примененных теринов.
    На сколько я смог понять, между словами "выравнивание" и "размер" у него подразумевается знак равенства.
  • KSergey © (07.06.08 11:45) [78]
    > KSergey ©   (07.06.08 09:42) [77]
    > Формально по ссылке наверное написано правильно,

    Беда только в том, что не про дельфи :)
    Но это обсуждение натолкнуло меня на мысль, что в дельфи у автора оно как-то примерно так же устроено, похоже.
 
Конференция "Основная" » Насколько адекватен SizeOf
Есть новые Нет новых   [134491   +8][b:0.001][p:0.007]