Thread: Calculating Endian type at runtime (and adapting to it)

  1. #1
    *this
    Join Date
    Mar 2005
    Posts
    498

    Calculating Endian type at runtime (and adapting to it)

    Well I've researched some endian calculating techniques and can't find a way to achieve what I want. I basically want to have a certain union type name be associated with the union that corresponds with the correct endian.

    This is what I have so far and I know it doesnt work, I'm not very good at preprocessor directives because I really dont ever use them, but I've tried everything so I just left it in the code. Here is the code, it calculates the correct endian (I think) but just doesn't define the right type.

    Code:
    #include <iostream>
    using namespace std;
    
    /////////////////////////////////////////////////
    typedef unsigned int CHAR32;
    //-----------------------------------------------
    // Breaks up 32 bits into blocks of 8 bits
    // BITBLOCKSB for Big-Endian
    // BITBLOCKSL for Little-Endian
    //-----------------------------------------------
    struct BITBLOCKSB {
       unsigned char    one;
       unsigned char    two;
       unsigned char  three;
       unsigned char   four;
    };
    
    struct BITBLOCKSL {
       unsigned char   four;
       unsigned char  three;
       unsigned char    two;
       unsigned char    one;
    };
    //-----------------------------------------------
    // Allows access to the bit blocks of a value
    // BITUNIONB for Big-Endian
    // BITUNIONL for Little-Endian
    //-----------------------------------------------
    typedef union {
       CHAR32      value;
       BITBLOCKSB   bits;
    } BITUNIONB;
    
    typedef union {
       CHAR32      value;
       BITBLOCKSL   bits;
    } BITUNIONL;
    //-----------------------------------------------
    // Current PC endian type
    //-----------------------------------------------
    bool ENDIAN() {
       short int bit = 1;
       char* byte = (char*) &bit;
       return (byte[0] ? true : false);
    }
    //-----------------------------------------------
    const bool BIGENDIAN = ENDIAN();
    //-----------------------------------------------   
    #if (BIGENDIAN)
       #define BITUNION BITUNIONB
    #else 
       #define BITUNION BITUNIONL
    #endif
    /////////////////////////////////////////////////
    
    int main() {
       BITUNION bitUnion;
       bitUnion.value = 254;
       cout << (int)bitUnion.bits.one << " " << (int)bitUnion.bits.two << " " 
          << (int)bitUnion.bits.three << " " << (int)bitUnion.bits.four;
          
       cout << endl << "Big Endian? " << (BIGENDIAN ? " Yes" : " No") << endl;
       cin.get();
       return 0;
    }
    Last edited by JoshR; 06-26-2005 at 01:05 AM.

  2. #2
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Code:
    int BigEndianSystem()
    {
        unsigned char SwapTest[2] = { 1, 0 };
      
        switch (*(unsigned short *)SwapTest)
        {
             case 0U :  return 0;   // little endian
             case 1U : return 1;   // big endian
             default: return -1;  // something else (middle endian!) - extremely rare AFAIK
        }
    }

  3. #3
    *this
    Join Date
    Mar 2005
    Posts
    498
    I already have a function that works, but I don't know how to correctly assign the type name BITUNION to the correct endian union (its the stuff in red thats troubling me)

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > const bool BIGENDIAN = ENDIAN();
    > #if (BIGENDIAN)
    These are two unrelated things, despite having the same name.

    The only way to manipulate the #if is by specifying either
    - in the source code #define BIGENDIAN 0 or #define BIGENDIAN 1
    - on the command line -DBIGENDIAN=0 or #define BIGENDIAN 1

    At which point, your assignment becomes illegal code as the preprocessor substitues
    const bool BIGENDIAN = ENDIAN();
    to be say for example
    const bool 1 = ENDIAN();

    Since you have no #define or -D options, when the pre-processor reaches
    #if (BIGENDIAN)
    it generates
    #define BIGENDIAN 0
    for you, then evaluates the #if expression.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    *this
    Join Date
    Mar 2005
    Posts
    498
    Ahhh just what I was not looking to hear, ya so preprocessor is really pre compile and everything, it isnt dynamic during runtime etc... do you have any suggestions of how I might approach this otherwise?

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > do you have any suggestions of how I might approach this otherwise?
    Create a function which has an interface which doesn't care about endian-ess, and which resolves the actual endian-ess in use (using your code to detect endian-ess) to control what actually happens.

    This can be quite a performance drag if you're doing lots of bit fiddling, so most people just go with the -DENDIAN type command line option when compiling.

    If you want, you can put a specific test at the start of main() say which checks the -D option with the apparent endian-ess returned by your function and complain if there's a mis-match.

    Run-time determination of endian-ess is problematic at best
    http://en.wikipedia.org/wiki/Endianness
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Oh OK. You want the name of different fields to change depending on endianness.

    The following will do a run time check, but that check only ever needs to be done once;

    Code:
    /////////////////////////////////////////////////
    typedef unsigned int CHAR32;
    
    typedef union {
       CHAR32      value;
       unsigned char bits[4];
    } BITUNION;
    
    int one;
    int two;
    int three;
    int four;
    
    
    //-----------------------------------------------
    // Current PC endian type
    //-----------------------------------------------
    bool ENDIAN() {
       short int bit = 1;
       char* byte = (char*) &bit;
       return (byte[0] ? true : false);
    }
    
    bool BIGENDIAN;
    
    int main() {
       if (BIGENDIAN = ENDIAN())   // yes, single = in here is deliberate
       {
            one = 0;
            two = 1;
            three = 2;
            four = 3;
       }
       else
       {
             one = 3;
             two = 2;
             three = 1;
             four = 0;
       }
       BITUNION bitUnion;
       bitUnion.value = 254;
       cout << (int)bitUnion.bits[one] << " " << (int)bitUnion.bits[two] << " " 
          << (int)bitUnion.bits[three] << " " << (int)bitUnion.bits[four];
          
       cout << endl << "Big Endian? " << (BIGENDIAN ? " Yes" : " No") << endl;
       cin.get();
       return 0;
    }

  8. #8
    *this
    Join Date
    Mar 2005
    Posts
    498
    Heres what I came up with, based on grumpy's code, and salems smartness.

    Code:
    #include <iostream>
    using namespace std;
    
    /////////////////////////////////////////////////
    typedef unsigned int CHAR32;
    //-----------------------------------------------
    // Current PC endian type
    //-----------------------------------------------
    bool ENDIAN() {
       short int bit = 1;
       char* byte = (char*) &bit;
       return (byte[0] ? false : true);
    }
    //-----------------------------------------------
    const bool BIGENDIAN = ENDIAN();
    //-----------------------------------------------
    // Breaks up 32 bits into blocks of 8 bits
    //-----------------------------------------------
    struct BITBLOCKS {
       unsigned char    one;
       unsigned char    two;
       unsigned char  three;
       unsigned char   four;
    };
    //-----------------------------------------------
    // Allows access to the bit blocks
    // Operator to help assign depending on endian 
    //-----------------------------------------------
    union BITUNION {
       CHAR32         value;
       BITBLOCKS       bits;
       void operator= (CHAR32 val);
    };
    
    void BITUNION::operator= (CHAR32 val) {
       value = val;
       if (BIGENDIAN)
       {
         bits.four  = val & 255; val >>= 8;
         bits.three = val & 255; val >>= 8;
         bits.two   = val & 255; val >>= 8;
         bits.one   = val & 255;
       }
    }
    //-----------------------------------------------   
    /////////////////////////////////////////////////
    
    int main() {
       BITUNION bitUnion;
       bitUnion = 6254;
       cout << (int)bitUnion.bits.one << " " << (int)bitUnion.bits.two << " " 
          << (int)bitUnion.bits.three << " " << (int)bitUnion.bits.four;
          
       cout << endl << "Big Endian? " << (BIGENDIAN ? " Yes" : " No") << endl;
       cin.get();
       return 0;
    }
    Last edited by JoshR; 06-26-2005 at 11:43 AM.

  9. #9
    *this
    Join Date
    Mar 2005
    Posts
    498
    Will someone with a little endian system test mine? lol I know thats an insane question to ask because nobody really thinks about their endian type, but if someone gets big endian == yes could you post the order of the numbers? thanks, I just want to see if it works corretly like it should.
    Last edited by JoshR; 06-26-2005 at 11:33 AM.

  10. #10
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Your endian test is inverted - it should be returning false for x86 systems, not true.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  11. #11
    *this
    Join Date
    Mar 2005
    Posts
    498
    k thanks

Popular pages Recent additions subscribe to a feed