Совместимое с MISRA обнаружение порядка следования байтов во время выполнения

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

Мне нужно проверить порядок байтов моего процессора во время выполнения. Я также должен делать это, оставаясь при этом совместимым с MISRA. Я использую C99.

MISRA не допускает преобразования между различными типами указателей, поэтому простое приведение uint32_t* к uint8_t* и разыменование, чтобы увидеть, какое значение содержит uint8_t, не допускается. Об использовании unions также не может быть и речи (MISRA не разрешает unions).

Я также попытался использовать memcmp, как в следующем фрагменте кода:

static endi get_endianess(void)
{
    uint32_t a = 1U;
    uint8_t b = 1U;

    return memcmp(&a, &b, 1) == 0 ? endi_little : endi_big;
}

но MISRA говорит, что The pointer arguments to the Standard Library function 'memcmp' are not pointers to qualified or unqualified versions of compatible types, что означает, что мне не удалось перехитрить его, преобразовав в допустимые указатели void* и позволив memcmp делать грязную работу.

Любые другие умные идеи будут оценены. Если у вас нет средства проверки MISRA, просто пришлите мне свою идею, и я дам вам знать, что говорит моя проверка.


person Omer Tuchfeld    schedule 20.02.2019    source источник
comment
Кажется, есть что-то, что может вам помочь здесь   -  person ryyker    schedule 20.02.2019
comment
Из любопытства, зачем вам нужно обнаружение во время выполнения? endianness не будет меняться от запуска к запуску!   -  person SergeyA    schedule 20.02.2019
comment
Мне тоже было бы интересно узнать, почему это нужно делать во время выполнения. Но если нужно, что мешает вам использовать endian.h? return __BYTE_ORDER == __LITTLE_ENDIAN ? endi_little : endi_big   -  person Christian Gibbons    schedule 20.02.2019
comment
Кроме того, я заметил, что вы отметили вопрос C99, но упомянули C11 в вопросе. Я не знаю, действительно ли это так сильно влияет на ваш вопрос, но, насколько я знаю, MISRA не поддерживает C11.   -  person Christian Gibbons    schedule 20.02.2019
comment
Сделайте это char вместо uint8_t. Все равно будет жаловаться?   -  person Eugene Sh.    schedule 20.02.2019
comment
@ryyker В большинстве примеров используется запрещенный союз. Я попробовал составные литералы, и это не удалось для Operand to a unary operator has an inappropriate essential type 'unsigned char' @SergeyA Это очень скучная причина, которую трудно объяснить, нет веской причины, по которой @ChristianGibbons endian.h недоступен для некоторых моих целей @ChristianGibbons Я хотел сказать C99, мой плохой @ ЕвгенийШ. Да, он все еще жалуется. Спасибо всем за ваши попытки помочь.   -  person Omer Tuchfeld    schedule 21.02.2019
comment
@SergeyA За исключением того, что это может быть на Power PC и теоретически на ARM (хотя я еще не сталкивался с ARM с прямым порядком байтов). Но что ж, было бы полным безумием переменно менять порядок байтов.   -  person Lundin    schedule 21.02.2019
comment
Кроме того, компилятору не обязательно иметь возможность надежно и переносимо определять порядок следования байтов во время компиляции.   -  person Lundin    schedule 21.02.2019
comment
Компилятор @Lundin может быть не в состоянии, но endian.h должен.   -  person SergeyA    schedule 21.02.2019
comment
@SergeyA Это даже не POSIX, а просто что-то из Linux. Определение порядка следования байтов ЦП или перестановка порядка байтов целых чисел не является ракетостроением.   -  person Lundin    schedule 21.02.2019
comment
MISRA не поддерживает C11 пока (но продолжайте следить за этим пространством в течение 24 часов или около того...)   -  person Andrew    schedule 25.02.2019


Ответы (2)


Я думаю, вы неправильно поняли правила MISRA-C. Такой код подходит:

 uint16_t u16 = 0xAABBu;
 bool big_endian = *(uint8_t*)&u16 == 0xAAu;

В правиле 11.3 MISRA-C:2012 есть исключение, позволяющее преобразовывать указатели в указатели на типы символов (которые можно смело рассматривать как uint8_t), но не наоборот. Цель правила — защитить от неправильного доступа и ошибок строгого алиасинга.


Кроме того, MISRA прекрасно разрешает union, правило против него носит рекомендательный характер, просто чтобы заставить людей остановиться и подумать, как они используют союзы. MISRA не позволяет использовать union ради хранения нескольких несвязанных вещей в одной и той же области памяти, таких как создание вариантов и прочая подобная чепуха. Но каламбур с контролируемым типом, где учитываются заполнение/выравнивание и порядок следования байтов, можно использовать с MISRA. То есть, если вам не нравится это рекомендательное правило. Лично я всегда игнорирую это в своих реализациях MISRA.

person Lundin    schedule 21.02.2019
comment
+1 за наблюдение за объединением ... Правило существует по той причине, что есть некоторое сомнительное поведение, хотя большинство компиляторов ведут себя. - person Andrew; 07.03.2019

Я предполагаю, что в контексте MISRA этот заголовок и эта функция могут быть недоступны, но:

#include <arpa/inet.h>

static endi get_endianness(void)
{
    return htons(0x0001u) == 0x0001u ? endi_big : endi_little;
}
person zwol    schedule 20.02.2019
comment
Этот заголовок недоступен для некоторых моих целей, но спасибо за попытку - person Omer Tuchfeld; 21.02.2019
comment
Для справки: если вы отправляете (у них есть) стандартную библиотеку в виде скомпилированных .so файлов (для каждой цели) вместе с ограниченным подмножеством заголовков, то эта функция, скорее всего, уже существует (в .so), но просто неизвестна. /не раскрыто. Если вы extern сделаете прототип функции, вы все равно сможете его использовать, несмотря на отсутствие заголовка. - person JWCS; 09.01.2020