C standard question?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • jan.chludzinski@gmail.com

    C standard question?

    Are the variables on the righthand side of an assignment statement
    treated strictly as values? That is, if in assigning to an "unsigned
    int" I shift a "unsigned char" 24 places to the left, can I trust that
    the compiler will use temp storage sufficient to hold the "unsigned
    int" and NOT result in an overflow (because I shifted an "unsigned
    char" 24 places)?

    Using gcc I tried the code below:

    #include <stdio.h>

    int main( int argc, char *argv[] )
    {
    unsigned char c[ 4 ] = { 0xff, 0xff, 0xff, 0xff };
    unsigned int ui;

    ui = (c[ 3 ] << 24) | (c[ 2 ] << 16) | (c[ 1 ] << 8) | c[ 0 ];
    fprintf( stderr, "ui = %x\n", ui );
    }

    and got:
    ui = ffffffff
    But validation through compilation is a dangerous thing!

    ---jski
  • Eric Sosman

    #2
    Re: C standard question?

    jan.chludzinski @gmail.com wrote:
    Are the variables on the righthand side of an assignment statement
    treated strictly as values?
    No, but mostly yes. In right-hand sides like `&x' or
    `sizeof x', the variable `x' is used only for its location
    or for its type, not for its value. But in "arithmetic "
    right-hand sides like `x + 3' or `x << 2' or just `x', the
    variable's value is used.
    That is, if in assigning to an "unsigned
    int" I shift a "unsigned char" 24 places to the left, can I trust that
    the compiler will use temp storage sufficient to hold the "unsigned
    int" and NOT result in an overflow (because I shifted an "unsigned
    char" 24 places)?
    No. The assignment target -- the left-hand side -- does
    not influence how the right-hand side is evaluated. On most
    systems[*] your `unsigned char' value will be promoted to a
    plain (signed) `int', which will then be shifted left 24 places.
    There'll be trouble if `int' has 24 or fewer bits (16, for
    example), or if the shift tries to slide a non-zero bit from
    a value position into the sign position.

    What you need is

    unsigned char uc = ...;
    unsigned int ui = (unsigned int)uc << 24;

    .... and this still contains the assumption that `int' is at
    least 25 bits wide.
    [*] Exception: On "exotic" systems like some digital signal
    processors, characters and ints have the same width and an
    `unsigned char' promotes to an `unsigned int' instead.
    Using gcc I tried the code below:
    >
    #include <stdio.h>
    >
    int main( int argc, char *argv[] )
    {
    unsigned char c[ 4 ] = { 0xff, 0xff, 0xff, 0xff };
    unsigned int ui;
    >
    ui = (c[ 3 ] << 24) | (c[ 2 ] << 16) | (c[ 1 ] << 8) | c[ 0 ];
    fprintf( stderr, "ui = %x\n", ui );
    }
    >
    and got:
    >
    >ui = ffffffff
    You were lucky. Or maybe unlucky.
    But validation through compilation is a dangerous thing!
    I'd have said "unreliable " rather than "dangerous, " but
    the sentiment is right.

    --
    Eric.Sosman@sun .com

    Comment

    • =?ISO-8859-1?Q?Tom=E1s_=D3_h=C9ilidhe?=

      #3
      Re: C standard question?

      On May 7, 8:20 pm, Eric Sosman <Eric.Sos...@su n.comwrote:
              unsigned int ui = (unsigned int)uc << 24;

      You wouldn't believe how many people do the likes of the following:

      char unsigned uc1, uc2;

      uc1 = 72;

      uc2 = ~uc1;

      1) uc1 gets promoted to a signed int
      2) The complement is gotten of this signed int
      3) When the signed int is converted back to unsigned char, the
      behaviour is implementation defined.

      There's no problem on a two's complement system, and of course most
      systems are two's complement, but still I'd definitely go with:

      uc2 = ~(unsigned)uc1;

      Comment

      • Flash Gordon

        #4
        Re: C standard question?

        jan.chludzinski @gmail.com wrote, On 07/05/08 19:44:
        Are the variables on the righthand side of an assignment statement
        treated strictly as values?
        That is not the question you intended to ask. I think you wanted to know
        if they are treated as values of the same type as the left hand side,
        and the answer is no.
        That is, if in assigning to an "unsigned
        int" I shift a "unsigned char" 24 places to the left, can I trust that
        the compiler will use temp storage sufficient to hold the "unsigned
        int" and NOT result in an overflow (because I shifted an "unsigned
        char" 24 places)?
        >
        Using gcc I tried the code below:
        >
        #include <stdio.h>
        >
        int main( int argc, char *argv[] )
        {
        unsigned char c[ 4 ] = { 0xff, 0xff, 0xff, 0xff };
        unsigned int ui;
        >
        ui = (c[ 3 ] << 24) | (c[ 2 ] << 16) | (c[ 1 ] << 8) | c[ 0 ];
        Each array element will be promoted to either int (if UCHAR_MAX <=
        INT_MAX) or unsigned int (if INT_MAX < UCHAR_MAX <= UINT_MAX). Since the
        latter is probably the case on your gcc implementation c[3]<<24 invoked
        undefined behaviour.
        fprintf( stderr, "ui = %x\n", ui );
        }
        >
        and got:
        >
        >ui = ffffffff
        >
        But validation through compilation is a dangerous thing!
        Indeed, as the behaviour is undefined in this case it was "luck" you got
        the answer you expected. You should cast to the correct unsigned type.
        Also be aware that (unsigned) int could be only 16 bits.
        --
        Flash Gordon

        Comment

        • CBFalconer

          #5
          Re: C standard question?

          jan.chludzinski @gmail.com wrote:
          >
          Are the variables on the righthand side of an assignment statement
          treated strictly as values? That is, if in assigning to an
          "unsigned int" I shift a "unsigned char" 24 places to the left,
          can I trust that the compiler will use temp storage sufficient to
          hold the "unsigned int" and NOT result in an overflow (because I
          shifted an "unsigned char" 24 places)?
          >
          Using gcc I tried the code below:
          >
          #include <stdio.h>
          int main( int argc, char *argv[] ) {
          unsigned char c[ 4 ] = { 0xff, 0xff, 0xff, 0xff };
          unsigned int ui;
          >
          ui = (c[ 3 ] << 24) | (c[ 2 ] << 16) | (c[ 1 ] << 8) | c[ 0 ];
          fprintf( stderr, "ui = %x\n", ui );
          }
          >
          and got: ui = ffffffff
          That only worked because the default int in your system was a 32
          bit quantity. You need to ensure that the various c[n]s are
          converted to a 32 bit quantity before shifting, i.e. cast them to
          unsigned long (not int), as in: "((unsigned int)c[3] << 24) |
          ((unsigned int)c[3] << 16) ...".

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


          ** Posted from http://www.teranews.com **

          Comment

          • Jack Klein

            #6
            Re: C standard question?

            On Wed, 7 May 2008 13:23:50 -0700 (PDT), Tomás Ó hÉilidhe
            <toe@lavabit.co mwrote in comp.lang.c:
            On May 7, 8:20 pm, Eric Sosman <Eric.Sos...@su n.comwrote:
            >
                    unsigned int ui = (unsigned int)uc << 24;
            >
            >
            You wouldn't believe how many people do the likes of the following:
            >
            char unsigned uc1, uc2;
            I would have a hard time believing that any people in the world other
            than you write the ridiculous "char unsigned".

            --
            Jack Klein
            Home: http://JK-Technology.Com
            FAQs for
            comp.lang.c http://c-faq.com/
            comp.lang.c++ http://www.parashift.com/c++-faq-lite/
            alt.comp.lang.l earn.c-c++

            Comment

            • Jack Klein

              #7
              Re: C standard question?

              On Wed, 7 May 2008 13:23:50 -0700 (PDT), Tomás Ó hÉilidhe
              <toe@lavabit.co mwrote in comp.lang.c:

              I should have read your reply all the way to the end before my first
              response. You made several errors.
              On May 7, 8:20 pm, Eric Sosman <Eric.Sos...@su n.comwrote:
              >
                      unsigned int ui = (unsigned int)uc << 24;
              >
              >
              You wouldn't believe how many people do the likes of the following:
              >
              char unsigned uc1, uc2;
              >
              uc1 = 72;
              >
              uc2 = ~uc1;
              >
              1) uc1 gets promoted to a signed int
              On many implementations , perhaps including all those you have ever
              used, uc1 gets promoted to signed int. There are implementations were
              uc1 will get promoted to unsigned int because UCHAR_MAX is greater
              than INT_MAX.
              2) The complement is gotten of this signed int
              Of course, on implementations where uc1 is promoted to unsigned int,
              the result of the complement is also an unsigned int.
              3) When the signed int is converted back to unsigned char, the
              behaviour is implementation defined.
              This is completely wrong regardless of whether unsigned char promotes
              to signed or unsigned int. Assignment of the value of a higher rank
              integer type, whether signed or unsigned, to a lesser rank unsigned
              integer type is 100% completely defined by the C standard. There is
              absolutely no implementation-defined behavior involved.
              There's no problem on a two's complement system, and of course most
              systems are two's complement, but still I'd definitely go with:
              >
              uc2 = ~(unsigned)uc1;
              On implementations where unsigned char promotes to signed int, the
              result of the complement is either a trap representation or
              implementation-defined, and that is regardless of the type of
              representation for negative signed integers. But if the complement
              does not produce undefined behavior by generating a trap
              representation, the assignment to unsigned char is always
              well-defined.

              --
              Jack Klein
              Home: http://JK-Technology.Com
              FAQs for
              comp.lang.c http://c-faq.com/
              comp.lang.c++ http://www.parashift.com/c++-faq-lite/
              alt.comp.lang.l earn.c-c++

              Comment

              • Chris H

                #8
                Re: C standard question?

                In message
                <29f39e17-0907-4e1c-aa89-945f767874f8@f3 6g2000hsa.googl egroups.com>,
                Tomás Ó hÉilidhe <toe@lavabit.co mwrites
                >On May 7, 8:20 pm, Eric Sosman <Eric.Sos...@su n.comwrote:
                >
                >        unsigned int ui = (unsigned int)uc << 24;
                >
                >
                >You wouldn't believe how many people do the likes of the following:
                >
                char unsigned uc1, uc2;
                Is that legal?

                I have seen it on a very old 8051 cross compiler but it was changed to
                the conventional "unsigned char" over a decade ago and I have not seen
                any other compiler that used it.
                --
                \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
                \/\/\/\/\ Chris Hills Staffs England /\/\/\/\/
                \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/



                Comment

                • =?ISO-8859-1?Q?Tom=E1s_=D3_h=C9ilidhe?=

                  #9
                  Re: C standard question?

                  On May 8, 4:44 am, Jack Klein <jackkl...@spam cop.netwrote:
                  1) uc1 gets promoted to a signed int
                  >
                  On many implementations , perhaps including all those you have ever
                  used, uc1 gets promoted to signed int.  There are implementations were
                  uc1 will get promoted to unsigned int because UCHAR_MAX is greater
                  than INT_MAX.

                  Yes, I'm aware. My post was a follow-up to Eric Sosman's post in which
                  he mentioned the promotion of unsigned char to signed int.

                  2) The complement is gotten of this signed int
                  >
                  Of course, on implementations where uc1 is promoted to unsigned int,
                  the result of the complement is also an unsigned int.

                  Correct. Just to be pedantic:

                  The complement of a signed int is a signed int.
                  The complement of an unsigned int is an unsigned int.

                  3) When the signed int is converted back to unsigned char, the
                  behaviour is implementation defined.
                  >
                  This is completely wrong regardless of whether unsigned char promotes
                  to signed or unsigned int.  Assignment of the value of a higher rank
                  integer type, whether signed or unsigned, to a lesser rank unsigned
                  integer type is 100% completely defined by the C standard.  There is
                  absolutely no implementation-defined behavior involved.

                  Sorry yes, you're right. Conversion from signed to unsigned happens
                  the same way on every system. I'd gotten confused with converting
                  unsigned to signed. For instance the behaviour of the following is
                  implementation defined:

                  int i = 72;
                  unsigned j = UINT_MAX;

                  i = j; /* The value that this puts in 'i' is
                  totally up to the compiler */

                  There's no problem on a two's complement system, and of course most
                  systems are two's complement, but still I'd definitely go with:
                  >
                      uc2 = ~(unsigned)uc1;
                  >
                  On implementations where unsigned char promotes to signed int, the
                  result of the complement is either a trap representation or
                  implementation-defined,

                  The only implementation-defined thing about it is the amount of 1's at
                  the start of it, depending on the amount of value-representationa l
                  bits in it. We can be sure what's happening with 8 least significant
                  bits though, regardless of whether is signed or unsigned.

                  and that is regardless of the type of
                  representation for negative signed integers.  But if the complement
                  does not produce undefined behavior by generating a trap
                  representation, the assignment to unsigned char is always
                  well-defined.

                  Yes it is.

                  Comment

                  • =?ISO-8859-1?Q?Tom=E1s_=D3_h=C9ilidhe?=

                    #10
                    Re: C standard question?

                    On May 8, 4:35 am, Jack Klein <jackkl...@spam cop.netwrote:
                    I would have a hard time believing that any people in the world other
                    than you write the ridiculous "char unsigned".

                    Have you taken an IQ test lately? Let's see if you can answer this
                    question:

                    Which two of these sentences convey the same information?

                    1) Today I saw a small dog beside the fence.
                    2) John takes sugar in his tea.
                    3) Beside the fence, I saw a small dog today.
                    4) Berlin is the capital of Germany.

                    If you're too mentally retarded to answer that question correctly then
                    you'll probably too imcompetent of a programmer to read other people's
                    code.

                    Comment

                    • =?ISO-8859-1?Q?Tom=E1s_=D3_h=C9ilidhe?=

                      #11
                      Re: C standard question?

                      On May 10, 6:55 pm, Tomás Ó hÉilidhe <t...@lavabit.c omwrote:
                      you'll
                      typo: you're

                      Comment

                      • Eric Sosman

                        #12
                        Re: C standard question?

                        Tomás Ó hÉilidhe wrote:
                        On May 8, 4:44 am, Jack Klein <jackkl...@spam cop.netwrote:
                        >
                        >>1) uc1 gets promoted to a signed int
                        >On many implementations , perhaps including all those you have ever
                        >used, uc1 gets promoted to signed int. There are implementations were
                        >uc1 will get promoted to unsigned int because UCHAR_MAX is greater
                        >than INT_MAX.
                        >
                        >
                        Yes, I'm aware. My post was a follow-up to Eric Sosman's post in which
                        he mentioned the promotion of unsigned char to signed int.
                        ... and in which I explicitly mentioned the possibility
                        of promotion to unsigned int instead. Nice of you to take
                        the time to repeat repeat repeat it it it.

                        --
                        Eric Sosman
                        esosman@ieee-dot-org.invalid

                        Comment

                        • Richard Heathfield

                          #13
                          Re: C standard question?

                          Tomás Ó hÉilidhe said:
                          On May 8, 4:35 am, Jack Klein <jackkl...@spam cop.netwrote:
                          >
                          >I would have a hard time believing that any people in the world other
                          >than you write the ridiculous "char unsigned".
                          >
                          >
                          Have you taken an IQ test lately?
                          Have you taken a clue test lately? I have a hard time believing you can
                          reasonably expect Jack to answer any of your many C questions after you've
                          addressed him like that...

                          <snip>
                          >
                          If you're too mentally retarded
                          ....or that. And his killfile will not be the only one to which you've
                          managed to gain entry with that masterly display of how not to be a
                          diplomat.

                          --
                          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

                          • =?ISO-8859-1?Q?Tom=E1s_=D3_h=C9ilidhe?=

                            #14
                            Re: C standard question?

                            On May 10, 7:21 pm, Richard Heathfield <r...@see.sig.i nvalidwrote:
                            And his killfile will not be the only one to which you've
                            managed to gain entry with that masterly display of how not to be a
                            diplomat.

                            And good job I'm not a diplomat, isn't it. I don't have to accomodate
                            people who are dickheads to me, which Mr Klein has been on more than
                            one occassion. That's the great thing about being a living, breathing
                            individual.

                            Also, I'm not your child and I don't seek any form of adoption, so if
                            you really want to be some sort of father or caring figure then you're
                            better off directing your attention at someone else.

                            I'm here to converse about C, not deal with mentally retarded
                            dickheads that are too stupid to get their head around a simple re-
                            ordering of words. And I'll re-iterate on that again: You TRULLY are
                            of extremely limited intelligence if you can't get your head around
                            "unsigned char" versus "char unsigned".

                            Oh, and if you have a killfile yourself, kindly add me to it, or at
                            the very least only respond to me if you've something to say about C.

                            Comment

                            • Eric Sosman

                              #15
                              Re: C standard question?

                              Tomás Ó hÉilidhe wrote:
                              [...]
                              I'm here to converse about C, not deal with mentally retarded
                              dickheads [...]
                              May all your conversations be as pleasant as this example.

                              --
                              Eric Sosman
                              esosman@ieee-dot-org.invalid

                              Comment

                              Working...