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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Бинарные файлы, Непонятное поведение 
:(
    Опции темы
sQu1rr
Дата 29.12.2014, 12:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 597
Регистрация: 11.11.2008
Где: london

Репутация: 3
Всего: 13



Цитата(konshyn @  29.12.2014,  10:21 Найти цитируемый пост)
Если говорить именно о типе unsigned long, то в стандарте С сказано, что значение должно быть минимум [0; 2^32 -1]. 
Не встречал ни одной платформы, где использовалось бы значение больше.

Приду домой проверю, но вроде как на x64 8 байт. вот такие дела.
PM MAIL Skype GTalk   Вверх
konshyn
Дата 29.12.2014, 12:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 295
Регистрация: 19.9.2013

Репутация: нет
Всего: нет



Цитата(sQu1rr @  29.12.2014,  12:44 Найти цитируемый пост)
Приду домой проверю, но вроде как на x64 8 байт. вот такие дела. 

О, Вы правы, действительно:)
Надо бы иногда проверять типы...
А то как вошло в привычку использовать uint типы, когда нужна точность в байтах, так и использую.


--------------------
«Потому что ценность акта действия в этой стране возрастает в несколько раз».
PM MAIL Skype   Вверх
DarthTon
Дата 30.12.2014, 16:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 106
Регистрация: 7.2.2009

Репутация: нет
Всего: 6



Размер long - 4 байта в винде, но 8 байт в x64 юникс-системах. Поэтому надо внимательно использовать его в кроссплатформенном коде.
PM MAIL   Вверх
wowka19
Дата 31.12.2014, 01:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 30.11.2011

Репутация: нет
Всего: нет



Спасибо. Учел ваши замечания:
Код

uint32_t crc32 = Crc32(TYPE_AND_DATA, 17); // 1
uint8_t * c = (uint8_t*) &crc32;
uint8_t inv[4];
for (int i = 0; i < 4; ++i) inv[i] = c[3-i]; //нужен обратный порядок для представления CRC32 чанка в PNG


1) Функция Crc32() возвращает тип ulong. Повлияет ли это на содержимое uint32_t crc32, если ulong будет больше 4 байт?
2) В последней строке я меняю порядок байт. Делаю я это чисто из практического наблюдения (в hex-редакторе увидел, что порядок не тот и поменял). Отсюда вопрос: этот код будет работать одинаково на всех платформах/компиляторах?


Это сообщение отредактировал(а) wowka19 - 31.12.2014, 01:28
PM MAIL   Вверх
konshyn
Дата 31.12.2014, 10:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 295
Регистрация: 19.9.2013

Репутация: нет
Всего: нет



Цитата(wowka19 @  31.12.2014,  01:26 Найти цитируемый пост)
1) Функция Crc32() возвращает тип ulong. Повлияет ли это на содержимое uint32_t crc32, если ulong будет больше 4 байт?

если возвращаемое значение будет больше 2^32 - 1, то в переменную типа uint32_t будет записано обрезанное до 4 байт значение, а так не должно влиять.

Цитата(wowka19 @  31.12.2014,  01:26 Найти цитируемый пост)
2) В последней строке я меняю порядок байт. Делаю я это чисто из практического наблюдения (в hex-редакторе увидел, что порядок не тот и поменял). Отсюда вопрос: этот код будет работать одинаково на всех платформах/компиляторах?

зачем менять просто так? есть порядок байт little endian и big endian, Вам уже писали выше. если Вы хотите переносимости, то должны решить, в каком порядке хранить байты, т.к. если вы будете просто менять, то в little endian поменяете на big endian и наоборот. И тогда на платформах с разным порядком байт программа из файла будет по-разному считывать значения. 
Храните, например, все содержимое файла в Big Endian формате, и тогда Вам придется менять порядок байт только на платформах с little endian. 


--------------------
«Потому что ценность акта действия в этой стране возрастает в несколько раз».
PM MAIL Skype   Вверх
wowka19
Дата 2.1.2015, 00:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 30.11.2011

Репутация: нет
Всего: нет



Почитал статью на хабре и не совсем понял.
Для уточнения/закрепления прочитанного:
Код

short s = 1000;
char * c = (char*) &s;
cout << *c;

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

Как я понял порядок байт задается НЕ на уровне ОС, а глубже/ниже и он неизменен. Так?
А конкретно на каком уровне он задается: на уровне прошивки BIOS или это вообще аппаратная причуда CPU?

Почему для UTF8 не важен порядок байт, ведь это многобайтная кодировка?

И как принято писать код, работающий с бинарными данными, чтобы он работал на любой машине одинаково?

Это сообщение отредактировал(а) wowka19 - 2.1.2015, 07:22
PM MAIL   Вверх
DarthTon
Дата 3.1.2015, 22:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 106
Регистрация: 7.2.2009

Репутация: нет
Всего: 6



Цитата

Как я понял порядок байт задается НЕ на уровне ОС, а глубже/ниже и он неизменен. Так?
А конкретно на каком уровне он задается: на уровне прошивки BIOS или это вообще аппаратная причуда CPU?

Это зависит от ЦП. Вся линейка х86 и х86-64 процессоров little-endian. Есть так же процессоры которые поддерживают оба порядка байт.
Цитата

Почему для UTF8 не важен порядок байт, ведь это многобайтная кодировка?

В ней каджый байт сам по себе, endianness же влият на порядок байт в цельных машинных словах.
Цитата

И как принято писать код, работающий с бинарными данными, чтобы он работал на любой машине одинаково?

Проверять endianness после прочтения данных, и при необходимости конвертировать в нужный порядок. Однако, если вы не собираетесь запускать свои программы на всях там SPARC, IBM POWER и прочих RISC'ах, этим можно не заморачиваться.
PM MAIL   Вверх
wowka19
Дата 6.1.2015, 09:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 30.11.2011

Репутация: нет
Всего: нет



Цитата(DarthTon @  3.1.2015,  22:51 Найти цитируемый пост)
Проверять endianness после прочтения данных, и при необходимости конвертировать в нужный порядок. Однако, если вы не собираетесь запускать свои программы на всях там SPARC, IBM POWER и прочих RISC'ах, этим можно не заморачиваться.

Нет. Я неправильно выразился. Уточню:
1. Как программе самостоятельно определить byte order текущей машины, чтобы потом правильно интерпретировать данные?
На ум приходит что-то вроде этого:
Код

uint16_t test_data = 1;
uint8_t * p_first_byte = (uint8_t*) &test_data;
if (*p_first_byte) // "01 00"
{
    // сейчас на текущей машине - little-endian,
    // но мне нужно писать в PNG, в котором принят big-endian,
    // поэтому я буду переставлять байты
}
else // "00 01"
{
    // сейчас на текущей машине - big-endian,
    // и поэтому в этот раз эта программа просто запишет данные в PNG-файл,
    // ничего не меняя
}

Но, подозреваю, что это костыль/велосипед и есть давно принятый де факто стандарт. Как пишите вы?

2. Как менять порядок байт без велосипедостроения? Какие есть устоявшиеся варианты, какие из них самые быстрые?

Спасибо за помощь!

Это сообщение отредактировал(а) wowka19 - 6.1.2015, 09:05
PM MAIL   Вверх
baldina
Дата 6.1.2015, 11:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



и про определение, и про преобразование
http://stackoverflow.com/questions/1001307...-in-a-c-program
PM MAIL   Вверх
wowka19
Дата 6.1.2015, 15:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 30.11.2011

Репутация: нет
Всего: нет



baldina, спасибо, но стало еще хуже:

1. топовое решение в по вашей ссылке:
Код

int is_big_endian(void)
{
    union {
        uint32_t i;
        char c[4];
    } bint = {0x01020304};

    return bint.c[0] == 1; 
}

Какое-то оно чересчур избыточно.
Зачем 4 байта когда и двух хватит?
Зачем такая абсурдная инициализация = 0x01020304, разве просто единицы (= 1) не хватит?
Да и если позанудствовать, то странно видеть в таком коде uint32_t и char[4] вместе, ведь они не всегда соразмерно, а это может быть критичным.

2. на втором месте такой вариант:
Код

if ( htonl(47) == 47 ) {
  // Big endian
} else {
  // Little endian.
}

Кажется это то что я искал. На самом деле мне не нужно знать какой порядок на машине, мне подойдет функция вроде htonl/ntohl, скрывающая всю кухню преобразований. Вот только это функции не из стандартной библиотеки, а какие-то юниксовые вроде. Замечу, что я использую Qt. Может в нем есть аналоги htonl/ntohl?

3. Копаясь в этих дебрях наткнулся на такой код:
Код

uint64_t htobe64(uint64_t x)
{
    __asm__("bswap %0" : "+r" (x));
    return x;
}

С асмом вообще не дружу, поэтому спрошу: неужели эта одна строчка меняет порядок на BE если он был LE и ничего не делает если он изначально был BE?

Это сообщение отредактировал(а) wowka19 - 6.1.2015, 15:33
PM MAIL   Вверх
baldina
Дата 6.1.2015, 16:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



Цитата(wowka19 @  6.1.2015,  15:02 Найти цитируемый пост)
ведь они не всегда соразмерно, а это может быть критичным

что не соразмерно?

Цитата(wowka19 @  6.1.2015,  15:02 Найти цитируемый пост)
На самом деле мне не нужно знать какой порядок на машине

на это вам с самого начала намекают. в вики (ссылку я давал раньше) про это тоже есть... для тех кто читает до конца  smile 

Цитата(wowka19 @  6.1.2015,  15:02 Найти цитируемый пост)
Вот только это функции не из стандартной библиотеки

это не стандартная библиотека, но есть на всех платформах (используется для работы с сетью)
http://msdn.microsoft.com/ru-ru/library/wi...6(v=vs.85).aspx
http://linux.die.net/man/3/htonl

PM MAIL   Вверх
fish9370
Дата 7.1.2015, 16:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 663
Регистрация: 15.4.2007
Где: Москва

Репутация: -1
Всего: 1



Цитата(wowka19 @  6.1.2015,  09:02 Найти цитируемый пост)
1. Как программе самостоятельно определить byte order текущей машины, чтобы потом правильно интерпретировать данные?


в сишном коде в юниксе часто используют примерно такие фокусы:

объявление:
endian.h
Код

#ifndef __BYTE_ORDER
#ifdef __linux__
#include <endian.h>
#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
#if defined(__OpenBSD__)
#include "compat.h"
#endif
#include <machine/endian.h>
#define __BYTE_ORDER BYTE_ORDER
#define __LITTLE_ENDIAN LITTLE_ENDIAN
#define __BIG_ENDIAN BIG_ENDIAN
#else

#ifndef __LITTLE_ENDIAN
#define __LITTLE_ENDIAN         1234
#endif

#ifndef __BIG_ENDIAN
#define __BIG_ENDIAN            4321
#endif

#ifdef __LITTLE_ENDIAN__
#define __BYTE_ORDER __LITTLE_ENDIAN
#endif /* __LITTLE_ENDIAN */

#if defined(sun) && defined(unix) && defined(sparc)
#define __BYTE_ORDER __BIG_ENDIAN
#endif /* sun unix sparc */

#endif /* linux */

#endif /* __BYTE_ORDER */

#ifndef __BYTE_ORDER
#error Need to know endianess
#endif /* __BYTE_ORDER */



compat.h
Код

#ifndef BYTE_ORDER
#define LITTLE_ENDIAN   1234
#define BIG_ENDIAN      4321

#ifdef __sparc__
#define BYTE_ORDER      BIG_ENDIAN
#else
#define BYTE_ORDER      LITTLE_ENDIAN
#endif
#endif

#ifndef __BYTE_ORDER
#define __LITTLE_ENDIAN LITTLE_ENDIAN
#define __BIG_ENDIAN BIG_ENDIAN
#define __BYTE_ORDER BYTE_ORDER
#endif



пример использования:
Код

struct option_header {
        /* Always keep in network byte order */
#if __BYTE_ORDER == __BIG_ENDIAN
        uint16_t flag:3;
        uint16_t option:13;
#else
#if __BYTE_ORDER == __LITTLE_ENDIAN
        uint16_t option:13;
        uint16_t flag:3;
#else
#error Byte order not defined
#endif
#endif
                uint8_t data[0];
};



код из одного известного крупного проекта


Это сообщение отредактировал(а) fish9370 - 7.1.2015, 17:00


--------------------
undefined
PM MAIL WWW ICQ   Вверх
DarthTon
Дата 9.1.2015, 01:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 106
Регистрация: 7.2.2009

Репутация: нет
Всего: 6



Цитата

Какое-то оно чересчур избыточно.
Зачем 4 байта когда и двух хватит?
Зачем такая абсурдная инициализация = 0x01020304, разве просто единицы (= 1) не хватит?
Да и если позанудствовать, то странно видеть в таком коде uint32_t и char[4] вместе, ведь они не всегда соразмерно, а это может быть критичным.

Да, 2 байт действительно хватит, но на скорости исполнения инструкций проверки это не отразится, избыточность тут чисто в коде. uint32_t всегда 4 байта и char всегда 1 байт, это вам не обычный int.
Цитата

на втором месте такой вариант:

Эта штука гораздо более избыточна чем первый вариант... Однако сама htonl конвертирует любой порядок байт в big endian.
Цитата

С асмом вообще не дружу, поэтому спрошу: неужели эта одна строчка меняет порядок на BE если он был LE и ничего не делает если он изначально был BE?

Нет, bswap всегда меняет порядок байт в слове, независимо от исходного порядка.
Цитата

в сишном коде в юниксе часто используют примерно такие фокусы:

Эта штука задает порядок статически, на этапе компиляции. ТСу же надо это определять в рантайме.

Это сообщение отредактировал(а) DarthTon - 9.1.2015, 01:47
PM MAIL   Вверх
wowka19
Дата 13.1.2015, 14:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 30.11.2011

Репутация: нет
Всего: нет



Был уверен, что в Qt есть аналог htonl и нашел его: qToBigEndian().
Но я заглянул в исходник и меня просто поразила реализация.
Код

template <> inline quint32 qbswap<quint32>(quint32 source)
{
    return 0
        | ((source & 0x000000ff) << 24)
        | ((source & 0x0000ff00) << 8)
        | ((source & 0x00ff0000) >> 8)
        | ((source & 0xff000000) >> 24);
}

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

Отсюда вопрос: почему проверка не на этапе выполнения? Это чересчур смелое допущение разработчиков Qt? Или на десктопных машинах, на которые рассчитан Qt, просто не выпускают CPU с сетевым порядком байт?

Интересно, в winsock2.h (mingw) функция htonl тоже не выполняет проверку...

Это сообщение отредактировал(а) wowka19 - 13.1.2015, 14:49
PM MAIL   Вверх
baldina
Дата 13.1.2015, 17:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



Цитата(wowka19 @  13.1.2015,  14:48 Найти цитируемый пост)
почему проверка не на этапе выполнения

потому что порядок байт это свойство процессора. изменить его можно только на процессорах, которые могут по-разному работать (тогда инициализацию порядка байт делает ОС). x86 - это всегда little-endian.
программа, скомпилированная под конкретную платформу, уже имеет заданный порядок.
qbswap(), как видно из названия, просто меняет порядок на обратный.
что касается qToBigEndian(), то её несколько вариантов (по результату условной компиляции), например
Код

#if Q_BYTE_ORDER == Q_BIG_ENDIAN
template <typename T> inline T qToBigEndian(T source)
{ return source; }

см. также http://www.ibm.com/developerworks/ru/library/au-endianc/

PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.4129 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.