LINUX.ORG.RU

Пусть тебе система сборки задаёт макрос, по-моему, это проще. На чистых макросах ты максимум, что можешь получить — динамическую проверку во время исполнения

XMs
()

Макросы на это не способны, нет вычисления, которое даст разные результаты. Компиляторы выставляют специфичные макросы, системы сборки, как подсказывают, могут использовать их или знание о целевой архитектуре.

xaizek
()

Есть «arpa/inet.h» (htonl() и т.п.), но в мануале по этим макросам написано что какие нибудь реализации могут требовать вместо «arpa/inet.h» - «netinet/inet.h». Может быть это можно как-то отследить в макросах?

normann
() автор топика

У меня так. И я реально работаю с процессорами с разным порядком.

#pragma once

#ifdef MATLAB_MEX_FILE
#   define INTEL_ORDER 1
#endif

#ifdef __LITTLE_ENDIAN__
#if __LITTLE_ENDIAN__ == 1
#   define INTEL_ORDER 1
#endif
#endif

#ifdef __BIG_ENDIAN__
#if __BIG_ENDIAN__ == 1
#   define MOTOROLA_ORDER 1
#endif
#endif

#ifdef __little_endian__
#if __little_endian__ == 1
#   define INTEL_ORDER 1
#endif
#endif

#if __big_endian__ == 1
#   define MOTOROLA_ORDER 1
#endif

#if defined (__BYTE_ORDER__)
#   if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#       define INTEL_ORDER 1
#   endif
#   if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#       define MOTOROLA_ORDER 1
#   endif
#endif

#if defined (__GLIBC__)
#   include <endian.h>
#   if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN
#       define INTEL_ORDER 1
#   endif
#   if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN
#       define MOTOROLA_ORDER 1
#   endif
#endif

#if  !defined(INTEL_ORDER) && !defined(MOTOROLA_ORDER)
#error "Unknow bit order"
#endif

#if defined(INTEL_ORDER)
#define ENDIANLES "LE"
#else
#define ENDIANLES "BE"
#endif

vromanov
()
Последнее исправление: vromanov (всего исправлений: 1)

Если «переносимо» — в рамках 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__
источник.
Ну и как уже сказали выше — по нормальному надо писать код которому всё равно на порядок байт хост-машины.

Deleted
()
Ответ на: комментарий от beastie

Тебя не должен волновать порядок байт на локальной машие.

Он меня не может не волновать, например если я пишу код для работы с протоколом ModBus (обмена по проводу), где слова надо формировать в «сетевом» порядке.

normann
() автор топика
Последнее исправление: normann (всего исправлений: 1)
Ответ на: комментарий от normann

И? Зачем тебе для этого знать локальный порядок байт?

LE data:

i = (data[3]<<0) | (data[2]<<8) | (data[1]<<16) | (data[0]<<24);

BE data:

i = (data[0]<<0) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);

При этом это корректно работает независимо от порядка байт i.

beastie ☕☕☕☕☕
()
Ответ на: комментарий от normann

Всё, что тебе надо знать — это две функции: htonl и ntohl.

beastie ☕☕☕☕☕
()
Ответ на: комментарий от beastie

Разберись со своим приведенным кодом, первая строчка ВСЕГДА будет менять порядок на отличный от машины, а вторая строчка вообще ошибка.

normann
() автор топика
Последнее исправление: normann (всего исправлений: 1)
Ответ на: комментарий от normann

первая строчка ВСЕГДА будет менять порядок на отличный от машины

Как это? Ну да, он перепутал LE и BE. Но в остальном должно быть нормально.

i-rinat ☕☕☕☕
()
Ответ на: комментарий от beastie

Работает одинаково. Но в зависимости от системы, записывается по разному.

i = | 00000000 | 10000000 | 00000000 | 00000000 |
i = i << 1

В Little-Endian и Big-Endian чему будет ровняться i ?

neon1ks
()
Ответ на: комментарий от neon1ks

Некорректная постановка вопроса. Куда записываются? То, что данные при записи на (локальный) диск тоже тоже надо маршилизировать, надеюсь ты слышишь не в первый раз.

Без разницы, от куда данные — с диска ли или из сети, для них есть формат. Из этого формата ты читаешь и дальше endianness тебя не волнует.

beastie ☕☕☕☕☕
()
Ответ на: комментарий от beastie

В оперативной памяти или в стеке.

В Little-Endian

i = | 00000001 | 00000000 | 00000000 | 00000000 |

В Big-Endian

i = | 00000000 | 00000000 | 00000001 | 00000000 |

Есть реализация функции htonll https://www.viva64.com/ru/k/0018/

там можно подсмотреть определение порядка байтов. Принцип в принципе один и тот же)

neon1ks
()
Последнее исправление: neon1ks (всего исправлений: 1)
Ответ на: комментарий от normann

Он меня не может не волновать, например если я пишу код для работы с протоколом ModBus (обмена по проводу), где слова надо формировать в «сетевом» порядке.

Скоро тебя ждёт удивительное открытие: различные дейвайсы плевать хотели на принятый в модбасе порядок. Так что сразу готовься переставлять слова (для смешанного) и байты. И это должна быть настройка индивидуальная для регистра, а не опция компиляции!

Для примера можешь глянуть спек на какой-нибудь немецкий девайс с модбасом. Немцы любят пихать кастомные типы и играть с порядком байт (на одном устройстве!).

anonymous
()
Ответ на: комментарий от neon1ks

Ты не понял главного. Ты не оперируешь с int на битовом уровне. Если ты это делаешь, ты делаешь что-то не правильно.

Что на BE машине 42>>1 == 21, что на LE машине. Грязные делишки CPU, что и как конкретно делает с int — никого не волнуют.

TL;DR: пример — достать 13 байт из int:

Правильный, портабельный метод, независимый от endianness:

bit = (i >> 13) & 1

Неправильный, ССЗБ метод, зависящий от endianness:

union {
  int  i;
  char c[4];
} x;
x.i = 42;
bit = (x.c[1] & 0x20) != 0;
beastie ☕☕☕☕☕
()
Ответ на: комментарий от Aswed

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

XMs
()
Ответ на: комментарий от XMs

А если человек какой-нибудь **_api.h пишет и там что-то вроде

/* stat mode_t wrapper type */
typedef union fmode_u {
    struct{
#if defined (BUILD_LITTLE_ENDIAN)
        unsigned arwx:3;
        unsigned grwx:3;
        unsigned urwx:3;
        unsigned vtx:1;
        unsigned gid:1;
        unsigned uid:1;
        unsigned type:4;
        uint16_t stub;
#elif defined(BUILD_BIG_ENDIAN)
        uint16_t stub;
        unsigned type:4;
        unsigned uid:1;
        unsigned gid:1;
        unsigned vtx:1;
        unsigned urwx:3;
        unsigned grwx:3;
        unsigned arwx:3;
#else
    #error Build with this endianess not realised
#endif
    }fields;
    uint32_t data;
} fmode_t;

.. до зарезу нужно, то как тогда выкручиваться нормальным людям?

SkyMaverick 👍👍
()
Последнее исправление: SkyMaverick (всего исправлений: 1)
Ответ на: комментарий от SkyMaverick

Писать сериализатор и десериализатор этого юниона, для разных архитектур свой. Запись и чтение будут происходить в Big-Endian, ибо network byte order, а дальше уже будет использоваться нативный порядок байт

XMs
()
Ответ на: комментарий от beastie

нет, таки в некоторых местах это очень важно. хотя бы для того, чтобы читать данные из сети и правильно их интерпретировать. но обычно это определяется на этапе компиляции, из макросов, определённых в компиляторе и при использовании стандартных макросов проблемы не возникает.

Iron_Bug ☕☕☕☕☕
()

Обычно, это делается на этапе компиляции с помощью системы сборки. Чтобы не таскать свои велосипеды по проектам. Смотри в сторону CMake. Все остальное, что тебе тут наговорили - велосипеды.

MuZHiK-2
()
Ответ на: комментарий от Iron_Bug

Для чтения и интерпретации байтиков из сети ПОРЯДОК БАЙТ НА ЛОКАЛЬНОЙ МАШИНЕ НЕ ВАЖЕН.

Как уже неоднократно тут пытается сказать beastie.

anonymous
()
Ответ на: комментарий от Iron_Bug

нет, таки в некоторых местах это очень важно. хотя бы для того, чтобы читать данные из сети и правильно их интерпретировать. но обычно это определяется на этапе компиляции, из макросов, определённых в компиляторе и при использовании стандартных макросов проблемы не возникает.

Что прямо вот реально пишешь #ifdef __LITTLE_ENDIAN__ и #ifdef __BIG_ENDIAN__ вместо того, чтобы заюзать ntohl()? Ну и изврат...

i-rinat ☕☕☕☕
()
Ответ на: комментарий от i-rinat

ntohl - часть стандартной позиксовской библиотеки. и она зависит от платформы. хотя позикс может быть не везде, ага.

и таки иногда, если байтики упакованы вдруг не по 2-4 байта, а по 3 или 6, например, приходится вручную их переставлять. и тогда да, ifdef, макросы и вот это всё.

Iron_Bug ☕☕☕☕☕
()
Последнее исправление: Iron_Bug (всего исправлений: 1)
Ответ на: комментарий от XMs

Ну офигеть теперь. А ты значит живешь в идеальном мире, где нет индусов и чужие структуры читать не надо, только свои и других замечательных программистов, которые всегда компилируют с первого раза.

Aswed
()
Ответ на: комментарий от Aswed

и чужие структуры читать не надо

Обычно для них уже есть десериализатор, если предполагается, что структура будет передаваться по сети либо читаться с диска. А даже если и нет, не так уж сложно его сделать. Для простых типов используем сетевой порядок при чтении и записи, битовые поля также пишем в Big-Endian, конвертируя, если надо

XMs
()
Ответ на: комментарий от XMs

С твоим подходом проще писать на жабе. И вообще - даешь чистый жабный процессор, чтобы никаких там бит и байт, а сразу объектами кидать по регистрам. Ну и конечно же встроенный в процессор мусоросборник.

anonymous
()
Ответ на: комментарий от anonymous

По-твоему, писать код, в основном не зависящий от архитектурных особенностей и обеспечивающий безболезненное сокрытие оных в местах, где без них никак — это плохо, и обеспечивать единые точки перехода не нужно, вместо этого на протяжении всего кода стоит держать эти особенности в памяти и обходить локально, я правильно тебя понимаю? Если да, то увы, не соглашусь — по мне такой подход чреват ошибками в куда большей степени

XMs
()
Ответ на: комментарий от anonymous

ту мач инстракшнс

На x86 такие выражения компилируются gcc в одну инструкцию (movl) для le и две инструкции (movl+bswap) для be.

i-rinat ☕☕☕☕
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.