Пусть тебе система сборки задаёт макрос, по-моему, это проще. На чистых макросах ты максимум, что можешь получить — динамическую проверку во время исполнения
Макросы на это не способны, нет вычисления, которое даст разные результаты. Компиляторы выставляют специфичные макросы, системы сборки, как подсказывают, могут использовать их или знание о целевой архитектуре.
Есть «arpa/inet.h» (htonl() и т.п.), но в мануале по этим макросам написано что какие нибудь реализации могут требовать вместо «arpa/inet.h» - «netinet/inet.h». Может быть это можно как-то отследить в макросах?
Если «переносимо» — в рамках gcc, clang и систем мимикирующих под них, то
__BYTE_ORDER__
__ORDER_LITTLE_ENDIAN__
__ORDER_BIG_ENDIAN__
__ORDER_PDP_ENDIAN__
__BYTE_ORDER__ is defined to one of the values __ORDER_LITTLE_ENDIAN__, __ORDER_BIG_ENDIAN__, or __ORDER_PDP_ENDIAN__ to reflect the layout of multi-byte and multi-word quantities in memory. If __BYTE_ORDER__ is equal to __ORDER_LITTLE_ENDIAN__ or __ORDER_BIG_ENDIAN__, then multi-byte and multi-word quantities are laid out identically: the byte (word) at the lowest address is the least significant or most significant byte (word) of the quantity, respectively. If __BYTE_ORDER__ is equal to __ORDER_PDP_ENDIAN__, then bytes in 16-bit words are laid out in a little-endian fashion, whereas the 16-bit subwords of a 32-bit quantity are laid out in big-endian fashion.
You should use these macros for testing like this:
/* Test for a little-endian machine */
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
источник.
Ну и как уже сказали выше — по нормальному надо писать код которому всё равно на порядок байт хост-машины.
Тебя не должен волновать порядок байт на локальной машие.
Он меня не может не волновать, например если я пишу код для работы с протоколом ModBus (обмена по проводу), где слова надо формировать в «сетевом» порядке.
Некорректная постановка вопроса. Куда записываются? То, что данные при записи на (локальный) диск тоже тоже надо маршилизировать, надеюсь ты слышишь не в первый раз.
Без разницы, от куда данные — с диска ли или из сети, для них есть формат. Из этого формата ты читаешь и дальше endianness тебя не волнует.
Он меня не может не волновать, например если я пишу код для работы с протоколом ModBus (обмена по проводу), где слова надо формировать в «сетевом» порядке.
Скоро тебя ждёт удивительное открытие: различные дейвайсы плевать хотели на принятый в модбасе порядок. Так что сразу готовься переставлять слова (для смешанного) и байты. И это должна быть настройка индивидуальная для регистра, а не опция компиляции!
Для примера можешь глянуть спек на какой-нибудь немецкий девайс с модбасом. Немцы любят пихать кастомные типы и играть с порядком байт (на одном устройстве!).
Нормальные люди при записи сериализуют данные, а при чтении десериализуют. Простые типы при этом пишутся в т. н. сетевом порядке, что исключает описанную тобой проблему
Писать сериализатор и десериализатор этого юниона, для разных архитектур свой. Запись и чтение будут происходить в Big-Endian, ибо network byte order, а дальше уже будет использоваться нативный порядок байт
нет, таки в некоторых местах это очень важно. хотя бы для того, чтобы читать данные из сети и правильно их интерпретировать. но обычно это определяется на этапе компиляции, из макросов, определённых в компиляторе и при использовании стандартных макросов проблемы не возникает.
Обычно, это делается на этапе компиляции с помощью системы сборки. Чтобы не таскать свои велосипеды по проектам. Смотри в сторону CMake. Все остальное, что тебе тут наговорили - велосипеды.
нет, таки в некоторых местах это очень важно. хотя бы для того, чтобы читать данные из сети и правильно их интерпретировать. но обычно это определяется на этапе компиляции, из макросов, определённых в компиляторе и при использовании стандартных макросов проблемы не возникает.
Что прямо вот реально пишешь #ifdef __LITTLE_ENDIAN__ и #ifdef __BIG_ENDIAN__ вместо того, чтобы заюзать ntohl()? Ну и изврат...
ntohl - часть стандартной позиксовской библиотеки. и она зависит от платформы. хотя позикс может быть не везде, ага.
и таки иногда, если байтики упакованы вдруг не по 2-4 байта, а по 3 или 6, например, приходится вручную их переставлять. и тогда да, ifdef, макросы и вот это всё.
Ну офигеть теперь. А ты значит живешь в идеальном мире, где нет индусов и чужие структуры читать не надо, только свои и других замечательных программистов, которые всегда компилируют с первого раза.
Обычно для них уже есть десериализатор, если предполагается, что структура будет передаваться по сети либо читаться с диска. А даже если и нет, не так уж сложно его сделать. Для простых типов используем сетевой порядок при чтении и записи, битовые поля также пишем в Big-Endian, конвертируя, если надо
С твоим подходом проще писать на жабе. И вообще - даешь чистый жабный процессор, чтобы никаких там бит и байт, а сразу объектами кидать по регистрам. Ну и конечно же встроенный в процессор мусоросборник.
По-твоему, писать код, в основном не зависящий от архитектурных особенностей и обеспечивающий безболезненное сокрытие оных в местах, где без них никак — это плохо, и обеспечивать единые точки перехода не нужно, вместо этого на протяжении всего кода стоит держать эти особенности в памяти и обходить локально, я правильно тебя понимаю? Если да, то увы, не соглашусь — по мне такой подход чреват ошибками в куда большей степени