You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@nuttx.apache.org by Tim Hardisty <ti...@hardisty.co.uk> on 2023/02/25 10:26:30 UTC

Byte to int32/big and little endian

As is so often the case, I need to pack an array of 4x uint8_t  into a uint32_t. Obviously there are many ways to do this and we all have our favourite. For NuttX:

1) have I missed a library function that does this already?
2) to cope with big and little end is there a NuttX CONFIG or other parameter that will give the endian-ness of the arch being built to ensure the byte packing is done correctly?

Thx, TimH.


RE: Byte to int32/big and little endian

Posted by Tim Hardisty <ti...@hardisty.co.uk>.
>From: Karel Kočí <cy...@email.cz>
>Sent: 26 February 2023 20:05
>
>Excerpts from Tim Hardisty's message of February 26, 2023 12:17 pm:
>>
>> On 25/02/2023, 11:47, "Karel Kočí" <cynerd@email.cz
><ma...@email.cz>> wrote:
>>
>>>I would use union (that is host ordering) and to convert to specific
>>>ordering you can use functions like htobe32 (big endian) and htole32
>>>(little endian),  those are available.
>>
>>> Excerpts from Tim Hardisty's message of February 25, 2023 11:26 am:
>>>> As is so often the case, I need to pack an array of 4x uint8_t into a
>uint32_t. Obviously there are many ways to do this and we all have our
>favourite. For NuttX:
>>>>
>>>> 1) have I missed a library function that does this already?
>>>> 2) to cope with big and little end is there a NuttX CONFIG or other
>parameter that will give the endian-ness of the arch being built to
>ensure the byte packing is done correctly?
>>
>> When using a union is it fair to assume that it is the responsibility
>of an app rather than a driver to sort endian-ness? I can find no
>references in the NuttX code base to changing endian-ness?
>>
>> Perhaps I'm over-thinking!
>>
>
>
>The example might be helpful. Lets start with absolute basic just to be
>sure we understand each other:
>
>  union {
>    uint32_t u32;
>    uint8_t u8[4];
>  } foo;
>
>  foo.u32 = 42; // This uses host's endianness and the compiler's
>responsibility
>  // The following prints most significant byte on the big endian and
>least
>  // significant byte on the little endian. Probably nothing new...
>  printf("%d\n", foo.u8[0]);
>
>The point is that compiler always knows the correct endianness and uses
>it. That is also what you accept as argument in most functions (commonly
>expected when order is not documented).
>
>Now when you are implementing chip specific driver you know endianness
>and thus there is no need to do swap when it matches.
>On the other hand, when you are implementing generic driver, expected to
>be running on any CPU, you need to ensure that swap happens when ever it
>is required (endianness doesn't match). The common approach, not just in
>NuttX, are those functions I pointed previously. The manual page for them
>is endian (https://man7.org/linux/man-pages/man3/endian.3.html).
>
>I think that you are overthinking it and you missed the library call. 😉

Yes, I missed the library call (never written portable drivers before, nor used public domain software like NuttX, so not aware of that sort of thing). And, in my case, this is reading 4 bytes in sequence from an 12c device and then packing them into a uint32_t to be read by the character driver read function.

I have found a fair few references suggesting unions are not portable if you write to one union element and read from another, and perhaps needing to be C89 compliant makes it worse?

I'm think a simple byte packing macro that takes account of CONFIG_ENDIAN_BIG (as per other drivers) is the safest - for me at least!

But this must be such a common thing to need to do I'm surprised I'm struggling to find an obvious example to refer to in chip driver code here - suggesting inconsistency and lack of "core" macro functions that would be useful?

Re: Byte to int32/big and little endian

Posted by Karel Kočí <cy...@email.cz>.
Excerpts from Tim Hardisty's message of February 26, 2023 12:17 pm:
> 
> On 25/02/2023, 11:47, "Karel Kočí" <cynerd@email.cz <ma...@email.cz>> wrote:
> 
>>I would use union (that is host ordering) and to convert to specific ordering 
>>you can use functions like htobe32 (big endian) and htole32 (little endian), 
>> those are available.
> 
>> Excerpts from Tim Hardisty's message of February 25, 2023 11:26 am:
>>> As is so often the case, I need to pack an array of 4x uint8_t into a uint32_t. Obviously there are many ways to do this and we all have our favourite. For NuttX:
>>> 
>>> 1) have I missed a library function that does this already?
>>> 2) to cope with big and little end is there a NuttX CONFIG or other parameter that will give the endian-ness of the arch being built to ensure the byte packing is done correctly?
> 
> When using a union is it fair to assume that it is the responsibility of an app rather than a driver to sort endian-ness? I can find no references in the NuttX code base to changing endian-ness?
> 
> Perhaps I'm over-thinking!
> 


The example might be helpful. Lets start with absolute basic just to be sure we 
understand each other:

  union {
    uint32_t u32;
    uint8_t u8[4];
  } foo;

  foo.u32 = 42; // This uses host's endianness and the compiler's responsibility
  // The following prints most significant byte on the big endian and least 
  // significant byte on the little endian. Probably nothing new...
  printf("%d\n", foo.u8[0]); 

The point is that compiler always knows the correct endianness and uses it. That 
is also what you accept as argument in most functions (commonly expected when 
order is not documented).

Now when you are implementing chip specific driver you know endianness and thus 
there is no need to do swap when it matches.
On the other hand, when you are implementing generic driver, expected to be 
running on any CPU, you need to ensure that swap happens when ever it is 
required (endianness doesn't match). The common approach, not just in NuttX, are 
those functions I pointed previously. The manual page for them is endian 
(https://man7.org/linux/man-pages/man3/endian.3.html).

I think that you are overthinking it and you missed the library call. 😉

Re: Byte to int32/big and little endian

Posted by Tim Hardisty <ti...@hardisty.co.uk>.
On 25/02/2023, 11:47, "Karel Kočí" <cynerd@email.cz <ma...@email.cz>> wrote:

>I would use union (that is host ordering) and to convert to specific ordering 
>you can use functions like htobe32 (big endian) and htole32 (little endian), 
> those are available.

> Excerpts from Tim Hardisty's message of February 25, 2023 11:26 am:
>> As is so often the case, I need to pack an array of 4x uint8_t into a uint32_t. Obviously there are many ways to do this and we all have our favourite. For NuttX:
>> 
>> 1) have I missed a library function that does this already?
>> 2) to cope with big and little end is there a NuttX CONFIG or other parameter that will give the endian-ness of the arch being built to ensure the byte packing is done correctly?

When using a union is it fair to assume that it is the responsibility of an app rather than a driver to sort endian-ness? I can find no references in the NuttX code base to changing endian-ness?

Perhaps I'm over-thinking!



Re: Byte to int32/big and little endian

Posted by Karel Kočí <cy...@email.cz>.
Hi

I would use union (that is host ordering) and to convert to specific ordering 
you can use functions like htobe32 (big endian) and htole32 (little endian), 
those are available.

K.K.

Excerpts from Tim Hardisty's message of February 25, 2023 11:26 am:
> As is so often the case, I need to pack an array of 4x uint8_t  into a uint32_t. Obviously there are many ways to do this and we all have our favourite. For NuttX:
> 
> 1) have I missed a library function that does this already?
> 2) to cope with big and little end is there a NuttX CONFIG or other parameter that will give the endian-ness of the arch being built to ensure the byte packing is done correctly?
> 
> Thx, TimH.
> 
>