Манипуляции с порядком байтов - есть ли для этого библиотека C?

В тех программах, которые я пишу (работающих с необработанными файлами данных), мне часто нужны функции для преобразования между прямым и обратным порядком байтов. Обычно я пишу их сам (об этом рассказывается во многих других постах здесь), но я не очень хочу этого делать по ряду причин, главная из которых — отсутствие тестирования. На самом деле я не хочу тратить целую вечность на тестирование своего кода в эмуляторе с обратным порядком байтов и часто просто опускаю код для машин с обратным порядком байтов. Я также предпочел бы использовать более быстрые функции, предоставляемые различными компиляторами, сохраняя при этом кроссплатформенность своих программ.

Единственное, что я могу найти, это вызовы сокетов, такие как htons(), но они требуют разных файлов #include на каждой платформе и некоторого кода GPL подобно этому, однако в этом конкретном файле, несмотря на его полноту, отсутствуют некоторые высокопроизводительные функции, предоставляемые некоторыми компиляторами. .

Итак, кто-нибудь знает библиотеку (в идеале просто файл .h), которая хорошо протестирована и предоставляет стандартный набор функций для работы с порядком байтов во многих компиляторах и платформах?


person Malvineous    schedule 03.04.2010    source источник
comment
Большинство компиляторов могут распознавать операции сдвига и маскирования как страницу подкачки с порядком байтов и заменять их гораздо лучшим кодом для большинства архитектур. Однако это не всегда верно, но если вы используете популярные платформы с компилятором, который популярен на этой платформе, вы, вероятно, получаете достойный код. Напишите несколько тестов, например, функцию копирования массива с перестановкой байтов, и посмотрите на сгенерированный код для вашей архитектуры.   -  person nategoose    schedule 04.04.2010
comment
Это интересно. Я предполагаю, что это означает, что вы можете использовать операции сдвига и маски по умолчанию для неизвестных платформ и надеяться, что компилятор поможет. Конечно, я бы предпочел заведомо работающую реализацию, чтобы мне не приходилось пробовать ее каждый раз, когда я добавляю в код новую платформу...!   -  person Malvineous    schedule 06.04.2010


Ответы (4)


За последнее десятилетие было несколько предложений о том, чтобы класс Boost (по крайней мере, для C++) делал именно это, но, к сожалению, ни одно из них так и не было реализовано.

Я не знаю лучшего обобщенного решения, чем набор функций htons().

person Dan Story    schedule 03.04.2010
comment
Один только что отправлен на проверку. Это выглядит очень красиво. boost.cowic.de/rc/endian/doc/index.html - person ; 08.09.2011

Проще всего просто не писать код, зависящий от порядка следования байтов. Вы никогда не должны заботиться о том, каков порядок байтов в системе, в которой вы работаете; единственное, что должно иметь значение, — это обязательный порядок следования байтов для любых внешних данных, которые вы читаете или записываете. Вы не должны спрашивать о преобразованиях между значениями с обратным порядком байтов и прямым порядком байтов, а скорее о преобразованиях из определенного порядка байтов в порядок байтов хоста, и вы можете написать этот код независимым от порядков байтов способом, который (почти) полностью переносим:

Например: предположим, что вы читаете 32-битное целое число с обратным порядком байтов из файлового потока:

/*
 * Note that callers should check feof(fp) afterward to verify that
 * there was enough data to read.
 */
uint32_t GetBE32(FILE* fp)
{
    uint32_t result;
    result  = fgetc(fp) << 24;
    result |= fgetc(fp) << 16;
    result |= fgetc(fp) <<  8;
    result |= fgetc(fp);
    return result;
}

uint32_t GetLE32(FILE* fp)
{
    uint32_t result;
    result  = fgetc(fp);
    result |= fgetc(fp) <<  8;
    result |= fgetc(fp) << 16;
    result |= fgetc(fp) << 24;
    return result;
}

(Я говорю «(почти) полностью переносимый», потому что предполагается, что на байт приходится 8 бит. Но если вы работаете в системе, где это не так, у вас, вероятно, возникнут большие проблемы при работе с внешним данные.)

person jamesdlin    schedule 03.04.2010
comment
Спасибо за ответ. Вы правы, меня не волнует порядок следования байтов системы, в которой я работаю, но когда я упомянул преобразование между прямым и обратным порядком байтов, я имел в виду преобразование между хостом и маленьким, а также хостом и большим. Ваш код похож на тот, который я использовал в прошлом, но я нашел его немного медленным при обработке нескольких гигабайт данных. (например, использование #ifdefs для исключения преобразования с прямым порядком байтов на платформах с прямым порядком байтов ускоряет работу.) Поэтому я ищу что-то более оптимизированное. - person Malvineous; 06.04.2010
comment
@jamesdlin: хех. Вы пробовали этот подход для чтения или записи поплавков или двойников? - person fearless_fool; 02.04.2017

В Linux есть <endian.h>

http://man7.org/linux/man-pages/man3/htole32.3.html

Мне было бы интересно узнать, поддерживают ли его другие операционные системы.

person Homer6    schedule 20.12.2013
comment
Похоже, что все Linux могут не иметь этих функций. Я только что попробовал grep htobe16 /usr/include/ -r на компьютере SUSE Linux Enterprise Desktop 10 SP4 (x86_64) безрезультатно. - person Paddu; 12.08.2014

Чего это стоит...

Как и в случае с OP, мне часто нужны подпрограммы с порядком байтов для перетасовки данных между разными машинами и протоколами. (В моем случае они мне нужны для встроенных процессоров, а не для большого железа.)

После нескольких итераций я разместил на Github библиотеку с порядком байтов, написанную на чистом C. Недостаток документации компенсируется комплексным модульным тестированием.

https://github.com/rdpoor/endian

Основное отличие endian от большинства библиотек с порядком байтов заключается в том, что она не предполагает побайтовой функции чтения или записи, а работает непосредственно с void * буферами памяти. Это дает компилятору свободу оптимизировать то, что он может, и в случае, если желаемый порядок байтов соответствует хост-компьютеру, он полностью сокращает перетасовку байтов.

person fearless_fool    schedule 19.01.2018