Баг... фича... в общем, косяк

Вопросы программирования на Free Pascal, использования компилятора и утилит.

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

Баг... фича... в общем, косяк

Сообщение Сергей Смирнов » 30.09.2006 10:49:27

Вот такая ситуация: объявляю запись
Код: Выделить всё
  PDataItem = ^TDataItem;
  TDataItem = record
    Kind: Integer;
    Base: Int64;
    Data: Pointer;
  end;

и когда дело доходит до выяснения её размера, с удивлением обнаруживаю, что это 24 байта. Ладно, пусть фрипаскаль выравнивает все поля на начало слова (8-байтного!!!). Тогда объявляю так:
Код: Выделить всё
  PDataItem = ^TDataItem;
  TDataItem = record
    Base: Int64;
    Kind: Integer;
    Data: Pointer;
  end;

Опаньки - размер уже 16, как и ожидалось. Я рад, вот только когда ничинаешь пользоваться таким объявлением:
Код: Выделить всё
        pNewData := PDataItem(pNewRow + FDataOffset + SizeOf(TDataItem) * i);
        pNewData^.Kind := ...;
        pNewData^.Base := ...;
        pNewData^.Data := ...;

наш дорогой компилятор всё также продолжает считать, что поля выровнены на границу Int64, т.е. размер записи - 24. Разумеется, это дело сопровождается ошибкой защиты памяти.

Отсюда вопрос: это я что-то не то делаю или хочу странного, либо таки это баг/фича?
Аватара пользователя
Сергей Смирнов
энтузиаст
 
Сообщения: 595
Зарегистрирован: 28.04.2005 13:23:25
Откуда: Москва

Сообщение Sergei I. Gorelkin » 30.09.2006 13:24:28

Честно говоря, я бы такое делать поостерегся - наверное, сказывается опыт программирования в Дельфи с его отсутствием арифметики с указателями.
А объявление записи с директивой packed не помогает?
И не совсем понятно, в том ли месте косяк - получается, что sizeof(TDataItem) в одном месте возвращает 16, а в другом 24, а в это поверить тяжело. Но тут, наверное, нужно получившийся ассемблерный код смотреть...
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Сергей Смирнов » 30.09.2006 23:15:37

Sergei I. Gorelkin писал(а):Честно говоря, я бы такое делать поостерегся - наверное, сказывается опыт программирования в Дельфи с его отсутствием арифметики с указателями.
А объявление записи с директивой packed не помогает?

А, да, забыл написать сразу. Ясное дело, packed помогает в том смысле, что sizeof(TDataItem) при любом порядке полей даёт 16. Но присвоение pNewData^, похоже, всё также рассчитывает на 24. Я, кстати, тоже так раньше не делал - вычислял вручную смещение каждого поля. А тут вот вдруг решил попробовать.
Sergei I. Gorelkin писал(а):И не совсем понятно, в том ли месте косяк - получается, что sizeof(TDataItem) в одном месте возвращает 16, а в другом 24, а в это поверить тяжело. Но тут, наверное, нужно получившийся ассемблерный код смотреть...
Ага, поверить трудно. И, кстати, замена Int64 на Double приводит к точно таким же результатам.
Аватара пользователя
Сергей Смирнов
энтузиаст
 
Сообщения: 595
Зарегистрирован: 28.04.2005 13:23:25
Откуда: Москва

Сообщение zub » 01.10.2006 12:07:32

>>наш дорогой компилятор всё также продолжает считать, что поля выровнены на границу Int64, т.е. размер записи - 24
а TDataItem к этому месту нигде не переопределяется? в свое время все особенности выравнивания FPC так и не просек, они меняются от версии к персии. в нужных местах испаользую {$A1}.
>> Ясное дело, packed помогает в том смысле, что sizeof(TDataItem) при любом порядке полей даёт 16. Но присвоение pNewData^, похоже, всё также рассчитывает на 24
таких вещей не наблюдаю хотя конструкции вида pNewData^. ... := ... ; использую часто
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Сообщение SAK » 01.10.2006 15:32:31

А если вместо
Код: Выделить всё
  pNewData := PDataItem(pNewRow + FDataOffset + SizeOf(TDataItem) * i);
явно написать
Код: Выделить всё
  pNewData := PDataItem(pNewRow + FDataOffset + 16 * i);
работает?
SAK
постоялец
 
Сообщения: 158
Зарегистрирован: 18.02.2006 00:45:14
Откуда: Тим

Сообщение Сергей Смирнов » 01.10.2006 17:34:45

Нет, не работает. Проблема не в том, что SizeOf возвращает неверное значение, а в том, что смещение при присваивании pNewData^. ... := ... ; вычисляется, видимо, не правильно. Не то чтобы я был в этом на 100% уверен, но очень похоже на то.
Аватара пользователя
Сергей Смирнов
энтузиаст
 
Сообщения: 595
Зарегистрирован: 28.04.2005 13:23:25
Откуда: Москва

Сообщение zub » 01.10.2006 18:37:50

pNewRow, FDataOffset как считаются? имхо тут ошибка.
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Сообщение SAK » 01.10.2006 19:44:46

Сергей Смирнов писал(а):Проблема не в том, что SizeOf возвращает неверное значение, а в том, что смещение при присваивании pNewData^. ... := ... ; вычисляется, видимо, не правильно.

Думаю, что скорее неправильно вычисляется значение pNewData.
А что такое pNewRow? Если это указатель на область данных, то может правильнее написать
Код: Выделить всё
pNewData := PDataItem(PChar(pNewRow) + FDataOffset + SizeOf(TDataItem) * i);

В общем не зная как используются переменные и даже их тип трудно рассуждать о причине ошибки.
SAK
постоялец
 
Сообщения: 158
Зарегистрирован: 18.02.2006 00:45:14
Откуда: Тим

Сообщение Сергей Смирнов » 01.10.2006 21:22:00

SAK писал(а):...PChar(pNewRow)...
Вот, кстати, это неплохая мысль. pNewRow - это просто указатель на ещё одну запись из пары полей и такое вот простое как у меня его использование может быть и не правильно. Когда проверю - отпишусь. Спасибо.
Последний раз редактировалось Сергей Смирнов 02.10.2006 11:51:40, всего редактировалось 1 раз.
Аватара пользователя
Сергей Смирнов
энтузиаст
 
Сообщения: 595
Зарегистрирован: 28.04.2005 13:23:25
Откуда: Москва

Сообщение Сергей Смирнов » 02.10.2006 11:51:12

Сергей Смирнов писал(а):
SAK писал(а):...PChar(pNewRow)...
Вот, кстати, это неплохая мысль. pNewRow - это просто указатель на ещё одну запись из пары полей и такое вот простое как у меня его использование может быть и не правильно. Когда проверю - отпишусь. Спасибо.

Проверил. Всё так и есть. Посыпаю голову пеплом и иду перечитывать факи по адресной арифметике :).
Аватара пользователя
Сергей Смирнов
энтузиаст
 
Сообщения: 595
Зарегистрирован: 28.04.2005 13:23:25
Откуда: Москва

Сообщение Mirage » 03.10.2006 20:14:00

Отличный пример того, почему не надо использовать адресную арифметику и вообще не стоило включать в язык.;)
А почему массив не использовать? Динамический...
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Сообщение Сергей Смирнов » 05.10.2006 10:18:08

Mirage писал(а):Отличный пример того, почему не надо использовать адресную арифметику и вообще не стоило включать в язык.;)
А почему массив не использовать? Динамический...
По мне, так это отличный пример того, что надо "учить матчасть", а не полагаться на собственные умозаключения о том, как оно там должно работать. :)
Аватара пользователя
Сергей Смирнов
энтузиаст
 
Сообщения: 595
Зарегистрирован: 28.04.2005 13:23:25
Откуда: Москва


Вернуться в Free Pascal Compiler

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

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

Рейтинг@Mail.ru