int to unsigned int conversions

A

Anupam

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
 
P

pete

Anupam said:
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.
 
M

Mark Gordon

On 3 Dec 2003 03:33:42 -0800
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
 
D

Dan Pop

In said:
#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
 
C

Christian Bau

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

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,733
Messages
2,569,439
Members
44,829
Latest member
PIXThurman

Latest Threads

Top