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)
Ответ на: комментарий от beastie

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

Имелось ввиду бит?

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

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

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

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

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

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

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

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

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

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

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

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

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