| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > непонятное содержимое массива после десериализации |
| Автор: boostcoder 27.5.2012, 21:29 | ||||
| привет. сериализую массив 'long double'ов(исходный массив инициализирован целыми: 1,2,3,4,5,6) в текстовый архив. после десериализации, при выводе полученного массива на консоль, все отображается корректно. проблема проявляется при сравнивании массивов с помощью memcmp(). при том, проблема проявилась только с текстовой сериализацей. hex дамп исходного массива:
hex дамп полученного массива:
что-то я даже не могу представить, почему это массивы содержат нужные значения, но при этом имеют разные дампы памяти подскажите из-за чего, и как лечить? спасибо. |
| Автор: Alexeis 27.5.2012, 21:45 |
| long double случаем не 10ти байтовый? Может элементы выравнены на границу 4х байт и собственно отличаются мусором, которым забиваются байты выравнивания? |
| Автор: Alexeis 27.5.2012, 22:06 |
Скорее всего long double реально занимает 10 байт, потому что сопроцессор больше не умеет, а вот компилятор для оптимизации по скорости увеличил размер типа добавив лишних 6 байт, которые он не читает и не пишет и в сопроцессор они никак не попадают, поэтому могут содержать в себе что угодно. Проверить можно так. Сначала заполнить память заборчиком из бит 0xAA дает последовательность 01010101 , при помощи memset, а затем записать поверх заборчика полезные данные. После чего глянуть дамп. В каждом из блоков по 16 байт должны проглядываться фрагменты заборчика. |
| Автор: boostcoder 27.5.2012, 22:14 | ||
оно так на 32ух битной машине. на 64ех битной - равняется 16. вот тому подтверждение: http://www.physics.uq.edu.au/people/foster/amd64_porting.html
таки вариант сейчас проверю... Добавлено через 7 минут и 41 секунду проверил еще и на венде. тоже 16. |
| Автор: mes 27.5.2012, 22:53 |
это не мешает быть полезными толъко 10 битам из 16.. |
| Автор: boostcoder 28.5.2012, 09:17 | ||
| хм.. без использования сериализации этот баг я немогу воспроизвести не на LWS, не на локальной машине код такой:
http://liveworkspace.org/code/3f721237a32a90a9afceb2a1d2434115 а вот если std::ostringstream и std::istringstream заменить на типы сериализатора/десериализатора - то ошибка восспроизведется. |
| Автор: borisbn 28.5.2012, 10:41 | ||||
если заменить на умножение, то получаем
http://liveworkspace.org/code/78c1ff19c35133d4ebbd7fb2fd099b7f Добавлено через 3 минуты и 12 секунд если long double заменить на long, то получаем equal. Наверное проблема в переводе плавающих чисел в строку и обратно. например, для числа 1,5 вполне может не оказаться двоичного представления, и ближайшее к нему будет равно 1,4(9), однако, при переводе его в строку, мы получим 1,5 |
| Автор: boostcoder 28.5.2012, 10:54 | ||
жуть какая
я тоже так думаю. вот только не знаю. на сколько такое поведение правильно.. |
| Автор: mes 28.5.2012, 10:54 | ||
а чем десериализируете? P.S. если вопрос о том могут ли равные значения бытьпредставлены разным набором битов, то ответ : могут |
| Автор: boostcoder 28.5.2012, 10:55 |
| исправленный код: http://liveworkspace.org/code/d57ddd3da320a456988591407d374eac Добавлено через 1 минуту и 13 секунд https://github.com/niXman/yas. |
| Автор: mes 28.5.2012, 10:56 |
для плавающих законно |
| Автор: boostcoder 28.5.2012, 11:02 |
| значит тест на сравнение байтового массива для таких типов некорректен? |
| Автор: borisbn 28.5.2012, 11:09 |
| хммм. а ведь проблема именно в long double. c float и с double - всё в порядке. http://liveworkspace.org/code/d85ee8ad014c23bcd4c3cfac76e72602 значит это не совсем верно |
| Автор: boostcoder 28.5.2012, 11:12 |
выходит так.. так может вовсе запретить использование 'long double' ? или оставить на страх и риск юзеров? |
| Автор: mes 28.5.2012, 11:16 | ||||||
да
просто не проявляется в этих условиях.. Добавлено через 1 минуту и 21 секунду
зачем запрещать если оно делает, что требуется ? |
| Автор: boostcoder 28.5.2012, 11:21 |
что-то я не уверен, что подразумевается под "оно делает, что требуется" |
| Автор: mes 28.5.2012, 12:02 | ||
что именно смущает ? |
| Автор: boostcoder 28.5.2012, 12:03 |
| неопределенность. получить бы еще ссылку на стандарт, где говорится об этой ситуации.. |
| Автор: mes 28.5.2012, 12:05 | ||||
различие бинарного представления ?
http://habrahabr.ru/post/112953/ Добавлено @ 12:05
гугль по IEEE 754 Добавлено через 2 минуты и 39 секунд та неопределенность о которой вы говорите свойственна всем вещественным числам, так что запретить придется даже флоат |
| Автор: boostcoder 28.5.2012, 12:11 |
| ааа, тогда получается все нормально всем спасибо. вопрос закрыт. |
| Автор: borisbn 28.5.2012, 12:17 | ||||
эт точно. сделай вместо
и получишь отличие уже на float http://liveworkspace.org/code/07bd523290435fce3118e1e6853568cc |
| Автор: boostcoder 28.5.2012, 12:27 |
ага. вижу. ясно. |
| Автор: Alexeis 28.5.2012, 13:17 | ||
Это актуально только для текстового представления. Бинарно же не будет вариаций типа 1.000e+1 / 0.100e+2 / 0.010e+3 , потому как числа с плавающей точкой не хранят позицию запятой и всегда сохраняются в одной форме. Думаю если сериализовать в бинарную форму, то после десериализации получим данные в точности. |
| Автор: borisbn 28.5.2012, 13:32 | ||
Да. Бинарная сеарелизация всё решит. Однако, совпадать будут только значения массива arr[ i ]-тые, а memcmp также может не совпадать. Я сделал, как Вы и говорили (заполнил массивы только не 0101010, а первый 0x00, а второй 0xFF). Вот рез-ты http://liveworkspace.org/code/15f9eee0856135c101d39b81dc15fa51 хмм. обнаружил интересную деталь: обычное присвоение long double (т.е. если вместо вытаскивания из stringstream'а сделать lda2[i] = lda1[i] ) копирует весь long double включая 0x00 на "незаполненных" местах, а вытаскивание из stingstream'а - нет |
| Автор: boostcoder 28.5.2012, 14:11 | ||
мдя.. |
| Автор: mes 28.5.2012, 14:38 | ||||
ну это естественно, что проблема возникает на стыках конвертации.. как может отличаться бинарное представление, если оно же и сохранено
не понял .. копирование просто копирует бинарное представление, а стрим конвертирует в/ из строки.. в чем нестыковка то ? |
| Автор: Alexeis 28.5.2012, 14:51 | ||
Я вижу только 2 байта заполненные FFFF вместо 6ти... Аа ну да. Этот компилятор определяет sizeof(long double) как 12 байт. 12 - 10 = 2 . Тогда вроде все как и ожидалось. |