Конференция "Основная" » Насколько адекватен SizeOf
 
  • 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.
    А по твоим словам ты же именно модуль меняешь
 
Конференция "Основная" » Насколько адекватен SizeOf
Есть новые Нет новых   [134491   +8][b:0][p:0.001]