0

I am converting a vxWorks application to Linux.

Previously, I had a union with a word and a struct so that when I accessed the members of the struct, I could use the word's layout to build my struct members.

However, I don't recall how I figured this out and it works on the vxWorks box. On my vxWorks instance, the layout is:

typedef union Status
{
    struct fields
    {
        uint32_t byteA : 1; // <31>
        uint32_t blank : 23; // <30:8>
        uint32_t bytesN : 8; // <7:0>
    } fields;

    uint32_t word;
}

I've already ran into some endian issues while porting from vxWorks to Linux. So figuring out the layout of uint32_t on linux is important.

  • 3
    shouldn't something like this do the trick? `uint32_t foobar = 0x00ff00ff; if (((char *) foobar)[0] == 0xff) /* one endianess */ else /* the other */` – Alexander Oh Oct 27 '11 at 20:36
  • Are you asking about http://stackoverflow.com/questions/6359629/union-hack-for-endian-testing-and-byte-swapping ? – Gnawme Oct 27 '11 at 21:32

2 Answers2

3

You can tell by taking a pointer to an int containing the value 0x01 and casting it to a char *. If the first value is equal to zero, then the system is big endian, otherwise it is little endian.

Here is an example:

#include <inttypes.h>
#include <stdio.h>

int main(void)
{
   uint32_t   val  = 0x01;
   char     * buff = (char *)&val;

   if (buff[0] == 0)
   {
      printf("Big endian\n");
   } else {
      printf("Little endian\n");
   };

   return(0);
}

I've used this method on Linux, Solaris, OS X, and FreeBSD.

David M. Syzdek
  • 15,360
  • 6
  • 30
  • 40
  • Yes, I know how to do this. But if `word` contains the number 40, I want that number in bytesN, not in blank or bytesA. That's why the layout is important. How uint32_t is laid out specifically. –  Oct 27 '11 at 20:46
  • @0A0D So you want to do this? `Status x; x.word=40; printf("%d", x.fields.bytesN);` – anatolyg Oct 27 '11 at 21:08
  • 1
    Your problem is that you are not reversing the order in which you access the bytes when access `Status.word`. On Big Endian ( hardware an integer is stored as B3,B2,B1,B0 however on a Little Endian an integer is stored as B0,B1,B2,B3. This means that on on big endian hardware `((Status .fields.byteN == 15) && (Status.word == 0x0F))` whereas on little endian hardware `((Status .fields.byteN == 15) && (Status.word == 0x0F000000))` When switching from a big endian platform rou either need to reverse the bit order of `Status.fields` or reverse the bit order used to access `Status.word` – David M. Syzdek Oct 27 '11 at 21:16
  • @anatolyg you should refine your question What do you want to do if not finding out the byte order? – Alexander Oh Oct 27 '11 at 21:46
1

From your comment to the other answer, you want whatever is stuffed into the word member of the union to appear in the fields.bytesN member. To achieve this you must either have some kind of pre-build process that lays out the field bit fields appropriately after detecting machine endianness, or create 2 structures, one for big endian and the other for little endian.

typedef union Status
{
    struct fieldsBE
    {
        uint32_t byteA : 1; // <31>
        uint32_t blank : 23; // <30:8>
        uint32_t bytesN : 8; // <7:0>
    } fieldsBE;

    struct fieldsLE
    {
        uint32_t bytesN : 8; // <7:0>
        uint32_t blank : 23; // <30:8>
        uint32_t byteA : 1; // <31>
    } fieldsLE;

    uint32_t word;
};

int main()
{
  bool isBigEndian = DetectEndianness(); // returns true if big endian

  Status status;

  status.word = 40;

  if( isBigEndian ) {
    uint8_t bytesN = status.fieldsBE.bytesN;

  } else {
    uint8_t bytesN = status.fieldsLE.bytesN;

  }
}

Of course, if you only want to support little endian in your port use the layout of fieldsLE instead of the original layout you've shown.

Community
  • 1
  • 1
Praetorian
  • 106,671
  • 19
  • 240
  • 328