Есть ли программный способ определить, используете ли вы архитектуру с прямым или обратным порядком байтов? Мне нужно иметь возможность писать код, который будет выполняться в системе Intel или PPC и использовать точно такой же код (т.е. без условной компиляции).
c++
algorithm
endianness
Джей Т
источник
источник
Ответы:
Мне не нравится метод, основанный на типе punning - его часто предупреждает компилятор. Именно для этого нужны профсоюзы!
Принцип эквивалентен регистру типов, как это было предложено другими, но это более понятно - и в соответствии с C99 гарантированно будет правильным. GCC предпочитает это по сравнению с прямым указателем.
Это также намного лучше, чем исправление порядка байтов во время компиляции - для ОС, которые поддерживают мульти-архитектуру (например, толстый бинарный файл на Mac OS X), это будет работать как для ppc / i386, так как в противном случае очень легко все испортить ,
источник
CHAR_BIT != 8
?Вы можете сделать это, установив int и замаскировав биты, но, вероятно, самый простой способ - это просто использовать встроенные операции преобразования сетевых байтов (так как сетевой порядок байтов всегда имеет старший порядковый номер).
Немного возиться можно было бы быстрее, но этот способ прост, понятен и его практически невозможно испортить.
источник
BSWAP
операции.Пожалуйста, смотрите эту статью :
источник
Вы можете использовать,
std::endian
если у вас есть доступ к компилятору C ++ 20, например, GCC 8+ или Clang 7+.Примечание:
std::endian
началось ,<type_traits>
но был перенесен на<bit>
на 2019 Cologne заседания. GCC 8, Clang 7, 8 и 9 имеют его, в<type_traits>
то время как GCC 9+ и Clang 10+ имеют его<bit>
.источник
Обычно это делается во время компиляции (особенно по соображениям производительности), используя файлы заголовков, доступные из компилятора, или создавайте свои собственные. В Linux у вас есть заголовочный файл "/usr/include/endian.h"
источник
Я удивился, что никто не упомянул макросы, которые препроцессор определяет по умолчанию. Хотя они будут варьироваться в зависимости от вашей платформы; они намного чище, чем необходимость написания собственного чека с порядком байтов.
Например; если мы посмотрим на встроенные макросы, которые определяет GCC (на машине X86-64):
На машине КПП я получаю:
(
:| gcc -dM -E -x c -
Волшебство распечатывает все встроенные макросы).источник
echo "\n" | gcc -x c -E -dM - |& grep -i 'endian'
ничего не возвращает, тогда как gcc 3.4.3 (в/usr/sfw/bin
любом случае) в Solaris имеет определение в этом направлении. Я видел похожие проблемы на VxWorks Tornado (gcc 2.95) -vs- VxWorks Workbench (gcc 3.4.4).Эмм ... Меня удивляет, что никто не понял, что компилятор просто оптимизирует тест и поместит фиксированный результат в качестве возвращаемого значения. Это делает все приведенные выше примеры кода практически бесполезными. Единственное, что будет возвращено - это порядок байтов во время компиляции! И да, я проверил все приведенные выше примеры. Вот пример с MSVC 9.0 (Visual Studio 2008).
Чистый код C
разборка
Возможно, можно отключить ЛЮБУЮ оптимизацию во время компиляции только для этой функции, но я не знаю. В противном случае это может быть возможно жестко закодировать в сборке, хотя это не переносимо. И даже тогда даже это может быть оптимизировано. Это заставляет меня думать, что мне нужен какой-то действительно дерьмовый ассемблер, реализовать один и тот же код для всех существующих процессоров / наборов инструкций, и, ну ... неважно.
Кроме того, кто-то здесь сказал, что порядок байтов не изменяется во время выполнения. НЕПРАВИЛЬНО. Есть машины с прямым порядком байтов. Их порядок может меняться в процессе исполнения. ТАКЖЕ, есть не только Little Endian и Big Endian, но и другие порядки байтов (что за слово).
Я ненавижу и люблю кодировать одновременно ...
источник
Объявите переменную int:
Теперь используйте char * указатели на различные его части и проверяйте, что находится в этих частях.
В зависимости от того, какой из них указывает на байт 0xFF, теперь вы можете обнаружить порядок байтов. Это требует sizeof (int)> sizeof (char), но это определенно верно для обсуждаемых платформ.
источник
Для получения более подробной информации, вы можете проверить эту статью codeproject Основные понятия о порядке байтов :
источник
C ++ способ был использовать повышение , где препроцессорные проверки и приведения разделены на части внутри очень тщательно протестированных библиотек.
Библиотека Predef (boost / prefn.h) распознает четыре различных типа байтов .
Endian библиотека была запланирована для представления стандарта C ++, а также поддерживает широкий спектр операций на обратный порядок байт-чувствительных данных.
Как указано в ответах выше, Endianness будет частью c ++ 20.
источник
Если вы не используете платформу, которая была портирована на процессоры PPC и Intel, вам придется выполнять условные компиляции, поскольку платформы PPC и Intel имеют совершенно разные аппаратные архитектуры, конвейеры, шины и т. Д. Это делает код сборки совершенно разным между два.
Что касается нахождения порядка байтов, сделайте следующее:
Вы также получите tempChar равным 0x12 или 0x34, из которого вы будете знать порядок байтов.
источник
stdint.h
и используйтеint16_t
в качестве доказательства будущего против короткого отличия на другой платформе.Я бы сделал что-то вроде этого:
Вдоль этих строк вы получите эффективную по времени функцию, которая выполняет вычисления только один раз.
источник
Как указано выше, используйте трюки союза.
Тем не менее, есть несколько проблем с теми, о которых говорилось выше, в особенности то, что доступ к невыровненной памяти общеизвестно медленен для большинства архитектур, и некоторые компиляторы даже не распознают такие постоянные предикаты, если только не выровнено слово.
Поскольку простой порядок байтов является скучным, здесь идет функция (шаблон), которая переворачивает ввод / вывод произвольного целого числа в соответствии с вашей спецификацией, независимо от архитектуры хоста.
Использование:
Для преобразования из данного порядкового номера в хост используйте:
host = endian(source, endian_of_source)
Чтобы преобразовать порядковый номер узла в указанный, используйте:
output = endian(hostsource, endian_you_want_to_output)
Результирующий код работает так же быстро, как и сборка рук на clang, на gcc он немного медленнее (развернутый &, <<, >>, | для каждого байта), но все еще приличный.
источник
источник
#define IS_BIGENDIAN() (*((char*) &((int){ 0x00ff })) == (0x00))
Не используйте
union
!C ++ не разрешает пробивание типов через
union
s!Чтение из поля объединения, которое не было последним записанным полем, является неопределенным поведением !
Многие компиляторы поддерживают это как расширения, но язык не дает никаких гарантий.
Смотрите этот ответ для более подробной информации:
https://stackoverflow.com/a/11996970
Есть только два правильных ответа, которые гарантированно будут переносимыми.
Первый ответ, если у вас есть доступ к системе, которая поддерживает C ++ 20,
это использовать
std::endian
из<type_traits>
заголовка.(На момент написания C ++ 20 еще не был выпущен, но если что-то не влияет на
std::endian
на включение, это должно быть предпочтительным способом проверки порядка байтов во время компиляции начиная с C ++ 20 и далее.)C ++ 20 г.в.
До C ++ 20 единственный верный ответ - хранить целое число, а затем проверять его первый байт через тип punning.
В отличие от использования
union
s, это явно разрешено системой типов C ++.Также важно помнить, что для оптимальной переносимости
static_cast
следует использовать,потому что
reinterpret_cast
реализация определена.C ++ 11 и далее
C ++ 11 и далее (без перечисления)
C ++ 98 / C ++ 03
источник
Это еще одно решение. Аналогично решению Эндрю Хэра.
источник
не проверено, но на мой взгляд, это должно работать? потому что это будет 0x01 на младшем порядке, и 0x00 на старшем порядке?
источник
Объявляет:
Мой начальный пост неправильно объявлен как "время компиляции". Это не так, это даже невозможно в текущем стандарте C ++. Constexpr НЕ означает, что функция всегда выполняет вычисления во время компиляции. Спасибо Ричарду Ходжесу за исправление.
время компиляции, не-макрос, C ++ 11 решение constexpr:
источник
Вы также можете сделать это через препроцессор, используя что-то вроде файла заголовка Boost, который можно найти в Boost Endian.
источник
Если заголовок endian не предназначен только для GCC, он предоставляет макросы, которые вы можете использовать.
источник
__BYTE_ORDER__
,__ORDER_LITTLE_ENDIAN__
а__ORDER_BIG_ENDIAN__
?Если вам не нужна условная компиляция, вы можете просто написать независимый код с порядком байтов. Вот пример (взят от Роба Пайка ):
Чтение целого числа, хранящегося в порядке с прямым порядком байтов на диске, с прямым порядком байтов:
Тот же код, пытающийся учесть машинный порядок байтов:
источник
источник
Как насчет этого?
источник
Вот еще одна версия C. Он определяет макрос, который вызывается
wicked_cast()
для вставки строкового типа через объединяющие литералы C99 и нестандартный__typeof__
оператор.Если целые числа являются однобайтовыми значениями, порядок байтов не имеет смысла и будет сгенерирована ошибка времени компиляции.
источник
То, как компиляторы C (по крайней мере, все, кого я знаю) работают с порядком байтов , должно быть решено во время компиляции. Даже для biendian процессоров (таких как ARM и MIPS) вы должны выбирать порядковый номер во время компиляции. Более того, порядок байтов определяется во всех распространенных форматах файлов для исполняемых файлов (таких как ELF). Несмотря на то, что можно создать двоичный двоичный код (возможно, для какого-нибудь эксплойта ARM-сервера?), Это, вероятно, должно быть сделано в сборке.
источник
Как указывает Coriiander, большинство (если не все) этих кодов здесь будут оптимизированы во время компиляции, поэтому сгенерированные двоичные файлы не будут проверять «порядковый номер» во время выполнения.
Было замечено, что данный исполняемый файл не должен запускаться в двух разных порядках байтов, но я понятия не имею, так ли это всегда, и мне кажется, что это проверка для меня во время компиляции. Итак, я закодировал эту функцию:
MinGW не смог оптимизировать этот код, хотя он и здесь оптимизирует другие коды. Я полагаю, что это потому, что я оставляю «случайное» значение, которое было выделено в меньшей байтовой памяти, как было (по крайней мере, 7 его битов), поэтому компилятор не может знать, что это случайное значение, и он не оптимизирует функция прочь
Я также закодировал функцию, чтобы проверка выполнялась только один раз, а возвращаемое значение сохраняется для следующих тестов.
источник
0x7FE
? Зачемmalloc()
вообще использовать ? это расточительно. И_BE
если (хотя и небольшая) утечка памяти и состояние гонки ожидают, то преимущества динамического кэширования результата не стоят проблем. Вместо этого я хотел бы сделать что-то более похожее на это:static const uint16_t teste = 1; int is_little_endian() { return (0x01 == ((uint8_t*)&teste)[0]); } int is_big_endian() { return (0x01 == ((uint8_t*)&teste)[1]); }
просто и эффективно, и гораздо меньше работы для выполнения во время выполнения.volatile
, или#pragma
и т. Д.хотя не существует быстрого и стандартного способа определить его, он выведет его:
источник
См. Endianness - Иллюстрация кода уровня C.
источник
Я изучал учебник: Компьютерная система: взгляд программиста , и есть проблема, чтобы определить, какой это порядковый номер в C-программе.
Я использовал функцию указателя, чтобы сделать это следующим образом:
Поскольку int занимает 4 байта, а char занимает только 1 байт. Мы могли бы использовать указатель на символ, чтобы указывать на int со значением 1. Таким образом, если компьютер имеет младший порядковый номер, символ, на который указывает указатель на символ , имеет значение 1, в противном случае его значение должно быть 0.
источник