| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Delphi: Общие вопросы > Работа с типами данных |
| Автор: unreg 29.11.2004, 03:55 |
| Столкнулся вот с такой интересной штукой: нужно читать данные из файла, у меня есть описание формата этого файла. Первая структура которая в него пишется выглядит примерно так: имя тип длина ---------------------------- time time_t 4 байта Vmax int 2 байта Smax int 2 байта FR float 4 байта (типы данных из Си) по этому описанию я создал свою структуру: TStruct = record time: cardinal; Vmax:word; Smax:word; FR: single; (потому, что этот тип занимает 4 байта и представляет число с плавающей точкой) далее через TFileStream считываю эту структуру. Первые три поля заполняются правильными значениями, а последнее совсем не тем чем надо. Тогда вместо Single ставлю array [0..3] of byte и опять считываю. далее, значение поля FR преобразую так: AValue:=Single(Struct.FR) и получаю правильное значение. Как это объяснить? Почему я не могу сразу считать в переменную типа Single и мне нужно действовать через массив? |
| Автор: ~FoX~ 29.11.2004, 09:57 |
| Single весит 2 байта. Используй Real. Добавлено @ 09:57 Заранее извеняюсь. мог и напутать |
| Автор: Guest 29.11.2004, 10:52 | ||
Что, собственно, и сделал. :-) |
| Автор: p0s0l 29.11.2004, 14:20 |
| Попробуй писать не record, а packed record... ЗЫ: позже, посмотрев еще раз вопрос, понял, что дело не в выравнивании... Тут и так всё выравнено... |
| Автор: _hunter 30.11.2004, 13:21 | ||
ну и показал бы чем оно заполняется ( желательно в bin ) и чем должно |
| Автор: dm9 30.11.2004, 14:19 |
| Извини, что немного не в тему, но, кажется, к сишному типу int будет ближе smallint, а не word |
| Автор: _hunter 30.11.2004, 14:24 | ||
| с какой это радости ( или под какую ось/компилятор )? из справки:
|
| Автор: dm9 30.11.2004, 14:55 | ||
_hunter, конечно, могу что-то не понимать, но сказано было, что сишный int занимает 2 байта:
Я уточнил, что если это так, и int этот не unsigned, то правильнее использовать SmallInt, а не Word. А под какой компилятор? Ну, под Borland C++ 3.1, например... Под ДОС. 32-разрядные версии уже будут использовать 4-байтный int (опять-таки, насколько я знаю), там надо брать Integer или LongWord в случае беззнакового числа. |
| Автор: unreg 1.12.2004, 08:02 |
| Я выбрал word потому, что отрицательных значений эти параметры не могут принимать физически. Так же они не могут принимать значения выше верхнего предела SmallInt. Разницы для меня в данном случае нет. Word - писать короче. Да и нет с ними проблемы. Что возвращается: если поставить Single, то 2,07446823360182E-40 (неправильно). Если array [0..3] of byte, то 50,0126495361328 (правильно). B двоичном сейчас нет возможности показать. |
| Автор: _hunter 1.12.2004, 12:34 |
| а хоть в hex ( к нему и приводить проще и видно лучше чем так ) |
| Автор: unreg 1.12.2004, 14:35 |
| Че-то, вообще, бред какой-то... Вот структура: TStruct = record time: cardinal; Vmax:word; Smax:word; FR: array [0..3] of byte; Завел еще массив a:array [0..3] of byte; Прочитал структуру и сделал Move(Struct.FR,a,4); массив заполнился следующим: 60 0 72 66. (правильно) Изменил описание FR на Single; Прочитал структуру и сделал Move(Struct.FR,a,4); массив заполнился следующим: 72 66 2 0. (не правильно) Не смотря на мои эксперименты, остальные поля заполнялись верно. А теперь самое интересное: Изменил описание массива а: var a:array [0..5] of byte; В структуре, поле FR описал точнно так же. Прочитал структуру и сделал Move(Struct.FR,a,6); массив заполнился следующим: 60 0 72 66 2 0 (дурдом на выезде) Да, еще забыл сказать, что эта струтктура в файле не единственная, он большой и там много всего. Тем не менее: Читаю по одному смещению. Количество байт строго определено. Что за кака? |
| Автор: <Spawn> 1.12.2004, 14:54 | ||||
| Покажи как ты читаешь данные в структуру. Я толька что проверил вот этот вариант:
И у меня все работает нормально:
Отсюда напрашивается один вывод - ты как то не верно читаешь данные в TStruct.FR |
| Автор: p0s0l 1.12.2004, 17:54 | ||||
| Судя по описанию - всё-таки возможно проблема в выравнивании... Только непонятно, откуда она берётся - ведь структура уже выравнена. Если бы вместо Cardinal был Word, то да, была бы 100% такая проблема, если в опциях компилятора выставлено выравнивание 4 или 8 байт... Единственное предположение, что ты где-то до описания этой структуры или в модулях, прописанных в Uses сделал описание кардинала таким:
Если делаешь Single - то он выравнивается по границе 4 байт, т.е. до FR вставятся два левых ненужных байта... Но опять же если бы ты переопределил тип Cardinal, то первые три поля структуры заполнились бы не теми данными (ведь time должен быть 4 байта)... Чтобы не гадать, скажи, что выдаёт у тебя SizeOf(TStruct) в случаях, если FR : array[0..3] of byte и FR : Single; Также, всё-таки, на всякий случай (чем черт не шутит ?), напиши так:
Или в опциях компилятора выстави Record Field Alignment в 1, или напиши вначале {$A1} Также вместо массива FR : array [0..3] of byte попробуй написать FR : DWORD или FR : Integer, и cделать Move (как ты уже делал) - что будет в таком случае ? Либо же проблема со чтением, как предположил <Spawn>... |
| Автор: unreg 6.12.2004, 05:30 | ||
| Извиняюсь, что долго не отвечал. Возможности не было. PoSol, действительно, размер структуры меняется. Полностью моя структура выглядит так:
В случае с Single: SizeOf(TMainStruct) = 40, в случае с array [0..3] of byte: SizeOf(TMainStruct) = 36. Читаю структуру из файла: var F:TFileStream; //читаю по нулевому смещению, структура находится в начале файла; F.Read(MainStruct,SizeOf(TMainStruct)); Видимо, дело действительно в выравнивании. Где в компиляторе находятся эти опции? И, если возможно, по-подробнее про выравнивание расскажите. Если я правильно понял, то под Single выделяется 8 байт как на Real, но значение имеют только 4? |
| Автор: <Spawn> 6.12.2004, 05:45 | ||
Сделай packed record, как тебе уже сказал p0s0l, и будет у тебя структура занимать 36 байт.
|
| Автор: unreg 8.12.2004, 04:10 |
| да я в курсе как делается packed record. |
| Автор: p0s0l 11.12.2004, 16:26 | ||||||
В твоём случае, С++ прога не выравнивает поля структуры - значит и тебе не нужно выравнивать...
Не совсем. Во-первых, всего 6 байт. Первые 2 байта - это "левые" байты, для выравнивания поля fr... Потом уже идёт 4 байта Singl'а... Почему тогда 40, а не 38 ? Потому что в конце структуры идут еще 2 выравнивающих байта (чтобы не только поля в структуре были выравнены, но и сами структуры)... |
| Автор: unreg 15.12.2004, 04:44 |
| Спасибо. Буду пользоваться, как ты и посоветовал. |