2

(First note that I know determining endianness at run-time is not an ideal solution and there are better ideas. Please don't bring that up)

I need to check the endianness of my CPU at run-time. I also have to do it while staying MISRA-compliant. I'm using C99.

MISRA doesn't allow conversion between different types of pointers, so simply casting a uint32_t* to uint8_t* and de-referencing to see what value the uint8_t holds is not allowed. Using unions is also out of the question (MISRA doesn't allow unions).

I also attempted to use memcmp like in the following piece of code:

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

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

but MISRA says that The pointer arguments to the Standard Library function 'memcmp' are not pointers to qualified or unqualified versions of compatible types, meaning I've failed to out-smart it by converting to legal void* pointers and letting memcmp do the dirty work.

Any other clever ideas will be appreciated. If you don't have a MISRA checker, just send me your idea and I'll let you know what my checker says

Omer Tuchfeld
  • 2,886
  • 1
  • 17
  • 24
  • 2
    There appears to be something that might help you _[here](https://stackoverflow.com/a/2103095/645128)_ – ryyker Feb 20 '19 at 19:50
  • 3
    Out of curiosity, **why** you need run-time detection? endianness will not change from run to run! – SergeyA Feb 20 '19 at 19:50
  • 1
    I, too, would be interested to know why it must be done at run time. But if you must, anything stopping you from using `endian.h`? `return __BYTE_ORDER == __LITTLE_ENDIAN ? endi_little : endi_big` – Christian Gibbons Feb 20 '19 at 20:06
  • 1
    Also, I noticed that you tagged the question `C99` but mentioned `C11` in the question. I don't know that it really affects your question so much, but last I knew, MISRA doesn't support `C11`. – Christian Gibbons Feb 20 '19 at 20:11
  • 1
    Make it `char` instead of `uint8_t`. Will it still complain? – Eugene Sh. Feb 20 '19 at 20:13
  • @ryyker Most examples use a union which is not allowed. I tried the compound literals one and it failed for `Operand to a unary operator has an inappropriate essential type 'unsigned char'` @SergeyA It's a very boring reason, hard to explain, no good reason @ChristianGibbons endian.h is not available on some of my targets @ChristianGibbons I meant to say C99, my bad @EugeneSh. Yes, it still complains Thank you all some much for your attempts to help though – Omer Tuchfeld Feb 21 '19 at 08:49
  • @SergeyA Except it can on Power PC, and in theory on ARM too (though I have yet to encounter a big endian ARM). But well, it would be complete madness to change endianess variably. – Lundin Feb 21 '19 at 13:46
  • Also, the compiler isn't necessary able to reliably and portably detect endianess at compile-time. – Lundin Feb 21 '19 at 13:47
  • @Lundin compiler might not be able, but `endian.h` should. – SergeyA Feb 21 '19 at 14:34
  • @SergeyA That's not even POSIX, just some Linux thing. Determining CPU endianess or swapping the byte order of integers isn't rocket science. – Lundin Feb 21 '19 at 14:44
  • MISRA doesn't support C11 **yet** (but keep watching this space, for 24 hours or so...) – Andrew Feb 25 '19 at 14:19

2 Answers2

3

I think you have misunderstood the MISRA-C rules. Code such as this is fine:

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

MISRA-C:2012 rule 11.3 has an exception allowing pointer conversions to pointer to character types (which uint8_t can safely be regarded as), but not the other way around. The purpose of the rule is to protect against misaligned access and strict aliasing bugs.


Also, MISRA allows union just fine, the rule against it is advisory, just to force people to stop and think how they are using unions. MISRA does not allow union for the sake of storing multiple unrelated things in the same memory area, such as creating variants and other such nonsense. But controlled type punning, where padding/alignment and endianess has been considered, can be used with MISRA. That is, if you don't like this advisory rule. Personally I always ignore it in my MISRA implementations.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • +1 for the union observation... the Rule is there for a reason - which is that there is some dubious behavior, although most compilers do behave. – Andrew Mar 07 '19 at 13:33
0

In a MISRA context, I suppose this header and this function might not be available, but:

#include <arpa/inet.h>

static endi get_endianness(void)
{
    return htons(0x0001u) == 0x0001u ? endi_big : endi_little;
}
zwol
  • 135,547
  • 38
  • 252
  • 361
  • This header is not available on some of my targets, but thank you for the attempt – Omer Tuchfeld Feb 21 '19 at 08:40
  • 1
    For the record, if you're shipping (they have) the standard library as compiled `.so` files (per target) along with a limited subset of the headers, then this function most likely already exists (within the `.so`), but is just unknown/not-exposed. If you `extern` the function prototype you would still be able to use it, despite not having the header. – JWCS Jan 09 '20 at 18:00