int to unsigned int conversions

Discussion in 'C Programming' started by Anupam, Dec 3, 2003.

  1. Anupam

    Anupam Guest

    Hi,
    This was asked on our school newsgroup by a friend of mine.
    He gave the following code and said that it did not print out
    the elements of the array. He asked for an explanation for this
    behaviour. I whittled this down a bit but I am unable to pin it
    to a reference from the standard which I would like to have given
    when explaining it.
    Ok here goes.

    #include <stdio.h>
    #include <stdlib.h>

    #define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
    int array[] = {23,34,12,17,204,99,16};

    int main(void)
    {
    int d;

    for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
    /* TOTAL_ELEMENTS is actually getting evaluated to an unsigned
    int. Since sizeof returns size_t which is unsigned int.
    I assume that this is the problem since the problem was reproduced
    if I used this line instead:
    for(d=-1;d <= ((unsigned int)7-2);d++)

    This for some reason is either implementation defined behaviour
    or undefined behaviour since I got two separate outputs from two
    compilers.. one being Turbo C and one the VC compiler.
    In one case it is not printing out any element of the array
    since the LHS is forcing itself up into unsigned int ...
    In the other case the unsigned int is coverted into an int, thus
    there are no problems.
    */

    printf("%d\n",array[d+1]);

    return EXIT_SUCCESS;
    }
    Would like to hear your comments regarding the above explanation.
    Regards,
    Anupam
     
    Anupam, Dec 3, 2003
    #1
    1. Advertising

  2. Anupam

    pete Guest

    Anupam wrote:
    >
    > Hi,
    > This was asked on our school newsgroup by a friend of mine.
    > He gave the following code and said that it did not print out
    > the elements of the array. He asked for an explanation for this
    > behaviour. I whittled this down a bit but I am unable to pin it
    > to a reference from the standard which I would like to have given
    > when explaining it.
    > Ok here goes.
    >
    > #include <stdio.h>
    > #include <stdlib.h>
    >
    > #define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
    > int array[] = {23,34,12,17,204,99,16};
    >
    > int main(void)
    > {
    > int d;
    >
    > for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
    > /* TOTAL_ELEMENTS is actually getting evaluated to an unsigned
    > int. Since sizeof returns size_t which is unsigned int.
    > I assume that this is the problem since the problem was reproduced
    > if I used this line instead:
    > for(d=-1;d <= ((unsigned int)7-2);d++)
    >
    > This for some reason is either implementation defined behaviour
    > or undefined behaviour since I got two separate outputs from two
    > compilers.. one being Turbo C and one the VC compiler.
    > In one case it is not printing out any element of the array
    > since the LHS is forcing itself up into unsigned int ...
    > In the other case the unsigned int is coverted into an int, thus
    > there are no problems.
    > */
    >
    > printf("%d\n",array[d+1]);
    >
    > return EXIT_SUCCESS;
    > }
    > Would like to hear your comments regarding the above explanation.


    for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
    should not print unless you have a situation where
    size_t gets converted to int, because that's the only way
    that -1 can be less than or equal to (size_t)5.
    If size_t is unsigned short and unsigned short
    has fewer value bits than int does, it should work.

    If -1 is converted to an unsigned type,
    then it is converted to the greatest value
    that the unsigned type is capable of representing.

    for(d=-1;d <= ((unsigned int)7-2);d++)
    should not print at all.

    for(d=-1;d <= (int)(TOTAL_ELEMENTS-2);d++)
    should print the array.

    --
    pete
     
    pete, Dec 3, 2003
    #2
    1. Advertising

  3. Anupam

    Mark Gordon Guest

    On 3 Dec 2003 03:33:42 -0800
    (Anupam) wrote:

    > Hi,
    > This was asked on our school newsgroup by a friend of mine.
    > He gave the following code and said that it did not print out
    > the elements of the array. He asked for an explanation for this
    > behaviour. I whittled this down a bit but I am unable to pin it
    > to a reference from the standard which I would like to have given
    > when explaining it.
    > Ok here goes.
    >
    > #include <stdio.h>
    > #include <stdlib.h>
    >
    > #define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
    > int array[] = {23,34,12,17,204,99,16};
    >
    > int main(void)
    > {
    > int d;
    >
    > for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
    > /* TOTAL_ELEMENTS is actually getting evaluated to an unsigned
    > int. Since sizeof returns size_t which is unsigned int.


    Is that true of both compilers you were trying? It is only required to
    be an unsigned integer type so it could be unsigned long.

    However, a more normal (and more reliable) way to do this loop is

    for (d=0; d<TOTAL_ELEMENTS; d++)

    to make certain that the above works for the maximum possible size of
    array you would have to declare d as being of type size_t.

    > I assume that this is the problem since the problem was reproduced
    > if I used this line instead:
    > for(d=-1;d <= ((unsigned int)7-2);d++)
    >
    > This for some reason is either implementation defined behaviour
    > or undefined behaviour since I got two separate outputs from two


    Implementation defined.

    > compilers.. one being Turbo C and one the VC compiler.
    > In one case it is not printing out any element of the array
    > since the LHS is forcing itself up into unsigned int ...
    > In the other case the unsigned int is coverted into an int, thus
    > there are no problems.
    > */
    >
    > printf("%d\n",array[d+1]);
    >
    > return EXIT_SUCCESS;
    > }
    > Would like to hear your comments regarding the above explanation.
    > Regards,


    You are on the right lines, however the exact promotions applied depend
    on how the implementation has chosen to define size_t, which on old DOS
    and Windows compilers may depend on the options used.

    If size_t is unsigned short and an int can represent all values of
    unsigned short then it will be promoted to int. This may be the case if
    you select the small memory model and an option that gives you 32 bit
    ints.

    Basically, your friend should not write his loops like that.

    Look up "Arithmetic Conversions", "Integral Promotion" and "Integral
    Conversion" for the full gory details
    --
    Mark Gordon
    Paid to be a Geek & a Senior Software Developer
    Although my email address says spamtrap, it is real and I read it.
     
    Mark Gordon, Dec 3, 2003
    #3
  4. Anupam

    Dan Pop Guest

    In <> (Anupam) writes:

    >#include <stdio.h>
    >#include <stdlib.h>
    >
    >#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
    >int array[] = {23,34,12,17,204,99,16};
    >
    >int main(void)
    >{
    > int d;
    >
    > for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
    >/* TOTAL_ELEMENTS is actually getting evaluated to an unsigned
    >int. Since sizeof returns size_t which is unsigned int.


    It's an unspecified usigned integer type.

    >I assume that this is the problem since the problem was reproduced
    >if I used this line instead:
    > for(d=-1;d <= ((unsigned int)7-2);d++)
    >
    > This for some reason is either implementation defined behaviour
    >or undefined behaviour since I got two separate outputs from two
    >compilers.. one being Turbo C and one the VC compiler.


    Except for the pathological case when size_t is unsigned char or unsigned
    short, the behaviour is well defined: d is converted to size_t (an
    unsigned integer type) before the comparison.

    > In one case it is not printing out any element of the array
    >since the LHS is forcing itself up into unsigned int ...


    This is the correct behaviour. When converting -1 to an unsigned type,
    the result is the maximum value representable by theat type.

    > In the other case the unsigned int is coverted into an int, thus
    >there are no problems.


    That compiler is broken. Neither Turbo C nor VC have a size_t that is
    subject to the integral promotions, therefore there is no way a size_t
    expression will be converted to int by the usual arithmetic conversions.

    The general rule is that if you mix signed and unsigned integers in the
    same expression, the signed integers must be non-negative in order to get
    what you intuitively expect. Fix your loop to the idiomatic

    for (d = 0; d < TOTAL_ELEMENTS; d++)
    printf("%d\n", array[d]);

    and everything will work just fine.

    Dan
    --
    Dan Pop
    DESY Zeuthen, RZ group
    Email:
     
    Dan Pop, Dec 3, 2003
    #4
  5. In article <>,
    (Anupam) wrote:

    > #include <stdio.h>
    > #include <stdlib.h>
    >
    > #define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
    > int array[] = {23,34,12,17,204,99,16};
    >
    > int main(void)
    > {
    > int d;
    >
    > for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
    > /* TOTAL_ELEMENTS is actually getting evaluated to an unsigned
    > int. Since sizeof returns size_t which is unsigned int.
    > I assume that this is the problem since the problem was reproduced
    > if I used this line instead:
    > for(d=-1;d <= ((unsigned int)7-2);d++)
    >
    > This for some reason is either implementation defined behaviour
    > or undefined behaviour since I got two separate outputs from two
    > compilers.. one being Turbo C and one the VC compiler.
    > In one case it is not printing out any element of the array
    > since the LHS is forcing itself up into unsigned int ...
    > In the other case the unsigned int is coverted into an int, thus
    > there are no problems.
    > */
    >
    > printf("%d\n",array[d+1]);
    >
    > return EXIT_SUCCESS;
    > }
    > Would like to hear your comments regarding the above explanation.
    > Regards,
    > Anupam


    It gives you the right idea, just very slightly inaccurate. size_t can
    be any unsigned type, not just unsigned int. But the important thing is
    that depending on the implementation, d may be converted to an unsigned
    type and therefore the loop will not print anything. Shows that you have
    to be very careful mixing signed and unsigned operands.
     
    Christian Bau, Dec 3, 2003
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Timo Freiberger
    Replies:
    3
    Views:
    974
    Bob Hairgrove
    Oct 30, 2004
  2. Replies:
    10
    Views:
    714
    Jasen Betts
    Aug 5, 2005
  3. er
    Replies:
    6
    Views:
    500
    Andre Kostur
    Sep 14, 2007
  4. ciccio

    int*unsigned int = unsigned?

    ciccio, Jun 4, 2010, in forum: C++
    Replies:
    2
    Views:
    417
    Öö Tiib
    Jun 4, 2010
  5. pozz
    Replies:
    12
    Views:
    760
    Tim Rentsch
    Mar 20, 2011
Loading...

Share This Page