Endian check macro

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Guillaume Dargaud

    Endian check macro

    Hello all,
    I tried to write a macro to check if a system is big endian or little endian
    with no success. Don't get me wrong, I have no problem writing a function or
    a one liner to do that, but I was trying to do it in a _macro_ with no
    side-effect (no global variable declaration). I suspect this is not
    possible.

    Anyone cares to prove me wrong ?
    --
    Guillaume Dargaud
    Climbing adventures, deep cold Antarctica tales and pictures, penguins, royalty-free photography, geek code and humor, plenty of quotes...



  • santosh

    #2
    Re: Endian check macro

    Guillaume Dargaud wrote:
    Hello all,
    I tried to write a macro to check if a system is big endian or little
    endian with no success. Don't get me wrong, I have no problem writing
    a function or a one liner to do that, but I was trying to do it in a
    _macro_ with no side-effect (no global variable declaration). I
    suspect this is not possible.
    >
    Anyone cares to prove me wrong ?
    #include <stdio.h>

    #define ENDIAN() { \
    volatile unsigned long ul = 1;\
    volatile unsigned char *p;\
    p = (volatile unsigned char *)&ul;\
    if (*p == 1)\
    puts("Little endian.");\
    else if (*(p+(sizeof(un signed long)-1)) == 1)\
    puts("Big endian.");\
    else puts("Unknown endian.");\
    }

    int main(void) {
    ENDIAN();
    return 0;
    }

    Comment

    • Ben Bacarisse

      #3
      Re: Endian check macro

      "Guillaume Dargaud" <use_the_form_o n_my_contact_pa ge@www.gdargaud .net>
      writes:
      I tried to write a macro to check if a system is big endian or little endian
      with no success. Don't get me wrong, I have no problem writing a function or
      a one liner to do that, but I was trying to do it in a _macro_ with no
      side-effect (no global variable declaration). I suspect this is not
      possible.
      >
      Anyone cares to prove me wrong ?
      In C99 you can use a compound literal to get something like the effect
      you want[1]:

      (union {short n; char b[sizeof(short)];}){.n = 1}.b[0]

      Wrap, however you want it, in a macro. unsigned char might better in
      general and there are a thousand issues with this code but without
      some details of what you are doing, I can't suggest anything more
      robust.

      [1] I am wary of code that tests for endian-ness since I've used
      machines where it is neither of the two commonly accepted
      alternatives.

      --
      Ben.

      Comment

      • Antoninus Twink

        #4
        Re: Endian check macro

        On 8 Jul 2008 at 11:35, santosh wrote:
        #define ENDIAN() { \
        volatile unsigned long ul = 1;\
        volatile unsigned char *p;\
        p = (volatile unsigned char *)&ul;\
        if (*p == 1)\
        puts("Little endian.");\
        else if (*(p+(sizeof(un signed long)-1)) == 1)\
        puts("Big endian.");\
        else puts("Unknown endian.");\
        }
        That's a remarkably practical solution, Santosh. I'm surprised no one's
        been along yet to warn you that (volatile unsigned char *)&ul might
        contain a trap representation and dereferencing it cause UB, or some
        such nonsense.

        Comment

        • Harald van =?UTF-8?b?RMSzaw==?=

          #5
          Re: Endian check macro

          On Tue, 08 Jul 2008 18:56:59 +0000, Antoninus Twink wrote:
          On 8 Jul 2008 at 11:35, santosh wrote:
          >#define ENDIAN() { \
          > volatile unsigned long ul = 1;\
          > volatile unsigned char *p;\
          > p = (volatile unsigned char *)&ul;\
          > if (*p == 1)\
          > puts("Little endian.");\
          > else if (*(p+(sizeof(un signed long)-1)) == 1)\
          > puts("Big endian.");\
          > else puts("Unknown endian.");\
          >}
          >
          That's a remarkably practical solution, Santosh. I'm surprised no one's
          been along yet to warn you that (volatile unsigned char *)&ul might
          contain a trap representation and dereferencing it cause UB, or some
          such nonsense.
          (volatile unsigned char *)&ul is a value expression. Objects can contain
          trap representations . Values cannot, since a trap representation, by
          definition, does not represent a value.

          If you were talking about *(volatile unsigned char *)&ul, then still,
          unsigned char is not allowed to have trap representations . unsigned char
          has 2**CHAR_BIT possible representations , and 2**CHAR_BIT possible values,
          so each value corresponds to exactly one bit pattern, and vice versa.

          If you were concerned with compatibility with C90, where accessing
          indeterminate values is disallowed unconditionally , then the code is still
          fine, because ul is initialised, and any object can be accessed as an
          array of unsigned char.

          There are some other comments that could be made about the code. I don't
          see why volatile is necessary here, and there _might_ be a few machines
          where the output is not factually correct. On those, the code is valid,
          and you'll get one of the three outputs, not a crash, not garbage, not
          anything else. (I'm not saying that's necessarily a good thing.) There is
          no undefined behaviour that I can see.

          Comment

          • Chris McDonald

            #6
            Re: Endian check macro

            santosh <santosh.k83@gm ail.comwrites:
            >Guillaume Dargaud wrote:
            >Hello all,
            >I tried to write a macro to check if a system is big endian or little
            >endian with no success. Don't get me wrong, I have no problem writing
            >a function or a one liner to do that, but I was trying to do it in a
            >_macro_ with no side-effect (no global variable declaration). I
            >suspect this is not possible.
            >>
            >Anyone cares to prove me wrong ?
            >#include <stdio.h>
            >#define ENDIAN() { \
            volatile unsigned long ul = 1;\
            volatile unsigned char *p;\
            p = (volatile unsigned char *)&ul;\
            if (*p == 1)\
            puts("Little endian.");\
            else if (*(p+(sizeof(un signed long)-1)) == 1)\
            puts("Big endian.");\
            else puts("Unknown endian.");\
            >}
            >int main(void) {
            ENDIAN();
            return 0;
            >}

            When the OP asked for a macro, and not a function, had I wrongly assumed
            that the intent was that the macro would be evaluated at compile-time,
            and not at run-time?

            --
            Chris.

            Comment

            • CBFalconer

              #7
              Re: Endian check macro

              santosh wrote:
              Guillaume Dargaud wrote:
              >
              >I tried to write a macro to check if a system is big endian or
              >little endian with no success. Don't get me wrong, I have no
              >problem writing a function or a one liner to do that, but I was
              >trying to do it in a _macro_ with no side-effect (no global
              >variable declaration). I suspect this is not possible.
              >>
              >Anyone cares to prove me wrong ?
              >
              #include <stdio.h>
              >
              #define ENDIAN() { \
              volatile unsigned long ul = 1;\
              volatile unsigned char *p;\
              p = (volatile unsigned char *)&ul;\
              if (*p == 1)\
              puts("Little endian.");\
              else if (*(p+(sizeof(un signed long)-1)) == 1)\
              puts("Big endian.");\
              else puts("Unknown endian.");\
              }
              ... snip ...
              Since (sizeof(long) == sizeof(char)) may be true, your first test
              on *p can be satisfied without needing a little endian system.

              --
              [mail]: Chuck F (cbfalconer at maineline dot net)
              [page]: <http://cbfalconer.home .att.net>
              Try the download section.


              Comment

              • Antoninus Twink

                #8
                Re: Endian check macro

                On 8 Jul 2008 at 21:54, Gordon Burditt wrote:
                *IF* your OS or compiler defines some preprocessor symbols that
                will enable you to figure out endianness, you could cheat using
                them. This is, of course, system-dependent. For example, on one
                OS, in <machine/endian.hyou have:
                [snip]

                I believe an
                #include <sys/types.h>
                will define BYTE_ORDER on most(?) Unices - certainly on BSD and Linux
                that's true. This will include machine-dependent endianness files for
                you.

                If the OP is aiming for portability, it's quite likely he'll be using
                the GNU autotools, in which case he could check out some of their
                macros, e.g. AC_C_BIGENDIAN etc.

                Comment

                • rahul

                  #9
                  Re: Endian check macro

                  On Jul 8, 5:08 pm, Ben Bacarisse <ben.use...@bsb .me.ukwrote:
                  [1] I am wary of code that tests for endian-ness since I've used
                  machines where it is neither of the two commonly accepted
                  alternatives.
                  But when we are reading binary packets which are not written on the
                  same architecture, or is following a particular style(tcp/ip uses big-
                  endian), we are forced to do the endian-ness tests.

                  Comment

                  • Richard Heathfield

                    #10
                    Re: Endian check macro

                    rahul said:
                    On Jul 8, 5:08 pm, Ben Bacarisse <ben.use...@bsb .me.ukwrote:
                    >
                    >[1] I am wary of code that tests for endian-ness since I've used
                    >machines where it is neither of the two commonly accepted
                    >alternatives .
                    But when we are reading binary packets which are not written on the
                    same architecture, or is following a particular style(tcp/ip uses big-
                    endian), we are forced to do the endian-ness tests.
                    Read what he's writing. He's saying that the assumption that an
                    architecture is either big-endian or little-endian is not always correct.
                    Middle-endian (sometimes called "NUXI") architectures do exist.

                    --
                    Richard Heathfield <http://www.cpax.org.uk >
                    Email: -http://www. +rjh@
                    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
                    "Usenet is a strange place" - dmr 29 July 1999

                    Comment

                    • santosh

                      #11
                      Re: Endian check macro

                      CBFalconer wrote:
                      santosh wrote:
                      >Guillaume Dargaud wrote:
                      >>
                      >>I tried to write a macro to check if a system is big endian or
                      >>little endian with no success. Don't get me wrong, I have no
                      >>problem writing a function or a one liner to do that, but I was
                      >>trying to do it in a _macro_ with no side-effect (no global
                      >>variable declaration). I suspect this is not possible.
                      >>>
                      >>Anyone cares to prove me wrong ?
                      >>
                      >#include <stdio.h>
                      >>
                      >#define ENDIAN() { \
                      > volatile unsigned long ul = 1;\
                      > volatile unsigned char *p;\
                      > p = (volatile unsigned char *)&ul;\
                      > if (*p == 1)\
                      > puts("Little endian.");\
                      > else if (*(p+(sizeof(un signed long)-1)) == 1)\
                      > puts("Big endian.");\
                      > else puts("Unknown endian.");\
                      >}
                      >... snip ...
                      >
                      Since (sizeof(long) == sizeof(char)) may be true, your first test
                      on *p can be satisfied without needing a little endian system.
                      Yes, that is a problem with the code, but C90 is restricted to unsigned
                      long as the largest portable integral type, so the solution to this
                      might have to use non-portable code.

                      Comment

                      • santosh

                        #12
                        Re: Endian check macro

                        Chris McDonald wrote:
                        santosh <santosh.k83@gm ail.comwrites:
                        >
                        >>Guillaume Dargaud wrote:
                        >
                        >>Hello all,
                        >>I tried to write a macro to check if a system is big endian or
                        >>little endian with no success. Don't get me wrong, I have no problem
                        >>writing a function or a one liner to do that, but I was trying to do
                        >>it in a _macro_ with no side-effect (no global variable
                        >>declaration ). I suspect this is not possible.
                        >>>
                        >>Anyone cares to prove me wrong ?
                        >
                        >>#include <stdio.h>
                        >
                        >>#define ENDIAN() { \
                        > volatile unsigned long ul = 1;\
                        > volatile unsigned char *p;\
                        > p = (volatile unsigned char *)&ul;\
                        > if (*p == 1)\
                        > puts("Little endian.");\
                        > else if (*(p+(sizeof(un signed long)-1)) == 1)\
                        > puts("Big endian.");\
                        > else puts("Unknown endian.");\
                        >>}
                        >
                        >>int main(void) {
                        > ENDIAN();
                        > return 0;
                        >>}
                        >
                        >
                        When the OP asked for a macro, and not a function, had I wrongly
                        assumed that the intent was that the macro would be evaluated at
                        compile-time, and not at run-time?
                        Hm, I didn't see it that way I admit. If the OP does want a compile-time
                        solution, then he might have to depend on non-standard headers, or
                        manually find out the endianness of the target and include the
                        appropriate defines. Executing a compile time program would not always
                        work if the target machine is not the machine that compiles the code.

                        Comment

                        • santosh

                          #13
                          Re: Endian check macro

                          Harald van D?k wrote:
                          >On 8 Jul 2008 at 11:35, santosh wrote:
                          >>#define ENDIAN() { \
                          >> volatile unsigned long ul = 1;\
                          >> volatile unsigned char *p;\
                          >> p = (volatile unsigned char *)&ul;\
                          >> if (*p == 1)\
                          >> puts("Little endian.");\
                          >> else if (*(p+(sizeof(un signed long)-1)) == 1)\
                          >> puts("Big endian.");\
                          >> else puts("Unknown endian.");\
                          >>}
                          [...]
                          There are some other comments that could be made about the code. I
                          don't see why volatile is necessary here,
                          I admit that I irrationally feared that the compiler might place the
                          variables in registers. Now I see that whatever it actually does, it
                          must still produce results according to the abstract machine, so yes,
                          the volatile is useless.
                          and there _might_ be a few
                          machines where the output is not factually correct.
                          Where sizeof(unsigned long) == sizeof(unsigned char). I suppose DSPs are
                          a possibility.
                          On those, the code
                          is valid, and you'll get one of the three outputs, not a crash, not
                          garbage, not anything else. (I'm not saying that's necessarily a good
                          thing.) There is no undefined behaviour that I can see.
                          Perhaps a style point, but would enclosing the code in a do/while loop
                          have been preferable to an unadorned block?

                          Comment

                          • Antoninus Twink

                            #14
                            Re: Endian check macro

                            On 9 Jul 2008 at 5:30, rahul wrote:
                            But when we are reading binary packets which are not written on the
                            same architecture, or is following a particular style(tcp/ip uses big-
                            endian), we are forced to do the endian-ness tests.
                            Not necessarily - htons() and friends exist to abstract away this detail
                            for networking applications.

                            Comment

                            Working...