unsigned int

L

lancer6238

Hi all,

I'm using RedHat Enterprise Linux 4 and gcc version 3.4.6. It is my
understanding that unsigned int can only represent positive numbers,
i.e. values 0 or larger. However, why is it that the code below works?

unsigned int i;
i = -5;
printf("%d\n", i);

The program prints -5. How is the negative number represented when "i"
should not have a sign bit?

Also, how do I verify that a data type, e.g. size_t, is indeed
unsigned, if an unsigned data type is able to represent a negative
number, like in the above example?

Thank you.

Regards,
Rayne
 
M

Mark Bluemel

Hi all,

I'm using RedHat Enterprise Linux 4 and gcc version 3.4.6. It is my
understanding that unsigned int can only represent positive numbers,
i.e. values 0 or larger.

That's true.
However, why is it that the code below works?

unsigned int i;
i = -5;

At this point, the signed value -5 is assigned into an unsigned value.
The standard specifies the rules. I don't recall the details off-hand
and am too lazy to look it up, but simple assignment of the binary
value representing -5 seems reasonable.
printf("%d\n", i);

You just lied to printf. You told it you would give it a signed number
and you passed an unsigned one.

Given that the unsigned int contains the same binary value as a signed
int containing -5, what would you expect printf to do?
The program prints -5. How is the negative number represented when "i"
should not have a sign bit?

Also, how do I verify that a data type, e.g. size_t, is indeed
unsigned, if an unsigned data type is able to represent a negative
number, like in the above example?

Your question is based on a misapprehension.
 
B

Barry Schwarz

Hi all,

I'm using RedHat Enterprise Linux 4 and gcc version 3.4.6. It is my
understanding that unsigned int can only represent positive numbers,
i.e. values 0 or larger. However, why is it that the code below works?

unsigned int i;
i = -5;
printf("%d\n", i);

Since %d requires the corresponding argument to be an int and you
passed printf and unsigned int, you have caused printf to invoke
undefined behavior. It is unfortunate the manifestation of undefined
behavior on your system produced something that confused you rather
than alerting you to the undefined behavior.

Replace the %d with %u and your output will make sense.
The program prints -5. How is the negative number represented when "i"
should not have a sign bit?

It is an unfortunate side effect of how many systems are structured.
Consider signed char and unsigned char (instead of int) on a common 2s
complement system. -5 is out of range for unsigned char. A value
within range is generated by adding 256. (Unsigned values are treated
as modulo max_value+1.) The resulting value of 251 is stored in the
unsigned char. This value is stored as 11111011. Since both types of
char are the same size, this byte can also be interpreted as signed.
As a signed value, that bit pattern is -5. If you print the value
with a signed conversion, you will get -5. If you print it with an
unsigned conversion, you will get 251.
Also, how do I verify that a data type, e.g. size_t, is indeed
unsigned, if an unsigned data type is able to represent a negative
number, like in the above example?

Whether or not you can trick printf into printing a negative value is
no indication of whether a type is signed or not. You could try the
following:
unsigned int x, y;
x = 0;
y = x - 1;
if (x > y) puts("signed");
else puts("unsigned");
and compare the results to similar code without the unsigned
qualifier.
 
S

Seebs

I'm using RedHat Enterprise Linux 4 and gcc version 3.4.6. It is my
understanding that unsigned int can only represent positive numbers,
i.e. values 0 or larger. However, why is it that the code below works?
Luck.

unsigned int i;
i = -5;
printf("%d\n", i);
The program prints -5. How is the negative number represented when "i"
should not have a sign bit?

You asked printf to print a signed number ("%d" prints a signed value).

As it happens, on your system, the bit pattern you get when you convert
"-5" to an unsigned int (equal to UINT_MAX - 5) happens to be the same as
the bit pattern you would get for "-5" as a signed int.
Also, how do I verify that a data type, e.g. size_t, is indeed
unsigned, if an unsigned data type is able to represent a negative
number, like in the above example?

You don't, but again, unsigned data types can't represent negative values,
but they can hold bit patterns which, if you interpreted them as signed
values, would look negative.

-s
 
S

Seebs

At this point, the signed value -5 is assigned into an unsigned value.
The standard specifies the rules. I don't recall the details off-hand
and am too lazy to look it up, but simple assignment of the binary
value representing -5 seems reasonable.

Nope, it's converted.

As it happens, the conversion is done by ... oh, !@#*!#, my previous post
was wrong. I said it was UINT_MAX - 5, but of course it's UINT_MAX - 4.

The conversion is done by repeatedly adding (TYPE_MAX + 1) until the value
becomes positive.

So -5 is negative. We add UINT_MAX+1, we get UINT_MAX - 4. Since UINT_MAX
is definitely more than 4, we're done; that's the value we use.

.... But, by amazing coincidence, on a typical 2's complement machine, this
happens to be equivalent to just copying the bits. :)

-s
 
M

mason

Hi all,

I'm using RedHat Enterprise Linux 4 and gcc version 3.4.6. It is my
understanding that unsigned int can only represent positive numbers,
i.e. values 0 or larger. However, why is it that the code below works?

unsigned int i;
i = -5;
printf("%d\n", i);

The program prints -5. How is the negative number represented when "i"
should not have a sign bit?

Also, how do I verify that a data type, e.g. size_t, is indeed
unsigned, if an unsigned data type is able to represent a negative
number, like in the above example?

Thank you.

Regards,
Rayne

you write macro for example x86 Little

positive x>>31 should be zero
 
G

Guest

|> At this point, the signed value -5 is assigned into an unsigned value.
|> The standard specifies the rules. I don't recall the details off-hand
|> and am too lazy to look it up, but simple assignment of the binary
|> value representing -5 seems reasonable.
|
| Nope, it's converted.

I think that's what Mark meant by "assigned into an unsigned value".
Poor wording, but that's what came across to me.


| As it happens, the conversion is done by ... oh, !@#*!#, my previous post
| was wrong. I said it was UINT_MAX - 5, but of course it's UINT_MAX - 4.

More technically to the letter of the standard: (UINT_MAX+1) - 5


| The conversion is done by repeatedly adding (TYPE_MAX + 1) until the value
| becomes positive.

That.


| So -5 is negative. We add UINT_MAX+1, we get UINT_MAX - 4. Since UINT_MAX
| is definitely more than 4, we're done; that's the value we use.

Since the result is definitely positive. Same thing, but more like what
the standard says (I happened to be reading that part yesterday).


| ... But, by amazing coincidence, on a typical 2's complement machine, this
| happens to be equivalent to just copying the bits. :)

Plus one more step. He used format %d which simply interpreted the bits as
if they were signed. So he's back at seeing "-5".
 
K

Keith Thompson

Also, how do I verify that a data type, e.g. size_t, is indeed
unsigned, if an unsigned data type is able to represent a negative
number, like in the above example?

(As several others have mentioned, your premise is incorrect; unsigned
types cannot represent negative numbers.)

For types defined by the standard, you can usually just check the
standard itself or any decent C refernece. For example, size_t is
guaranteed to be an unsigned type.

More generally, there are ways to detect at compile time whether a
type is signed or unsigned. For example:

#include <stdio.h>
#include <stddef.h>
#include <time.h>

#define KIND(type) \
( (type)1/(type)2 > (type)0 ? "floating-point" : \
-(type)1 > 0 ? "unsigned" : \
"signed" )

int main(void)
{
printf("char is %s\n", KIND(char));
printf("unsigned char is %s\n", KIND(unsigned char));
printf("signed char is %s\n", KIND(signed char));
printf("short is %s\n", KIND(short));
printf("unsigned short is %s\n", KIND(unsigned short));
printf("int is %s\n", KIND(int));
printf("unsigned int is %s\n", KIND(unsigned int));
printf("size_t is %s\n", KIND(size_t));
printf("ptrdiff_t is %s\n", KIND(ptrdiff_t));
printf("time_t is %s\n", KIND(time_t));
printf("double is %s\n", KIND(double));
return 0;
}

But note that this fails for unsigned types narrower than int, due to
integer promotions.

On the other hand, this is rarely useful. Usually if you're using a
type you should already know its characteristics.
 
P

Peter Nilsson

... there are ways to detect at compile time whether a
type is signed or unsigned.  For example:

#define KIND(type) \
    ( (type)1/(type)2 > (type)0 ? "floating-point" : \
      -(type)1 > 0 ? "unsigned" : \
      "signed" )

#define KIND(type) \
( (type) 1 / (type) 2 > 0 ? "floating-point" \
: (type) -1 > 0 ? "unsigned" \
: "signed" )
 
K

Keith Thompson

Peter Nilsson said:
#define KIND(type) \
( (type) 1 / (type) 2 > 0 ? "floating-point" \
: (type) -1 > 0 ? "unsigned" \
: "signed" )

Yes, that does it. Thanks.
 
B

Barry Schwarz

Actually, it can.
I don't know what I was thinking.

As a C expression, if it is evaluated as an unsigned int, surely its
value must be 0.

In a discussion of how negative values are conceptually adjusted when
assigned to an unsigned object, just as surely the expression is not a
C one but an arithmetic one.
 
P

Peter Nilsson

It has to be since UINT_MAX is of type unsigned int.
Yes.


so (int)((UINT_MAX+1)-1)==(int)UINT_MAX    ==-1

If UINT_MAX == INT_MAX, then (int) UINT_MAX is just INT_MAX,
which isn't -1. If UINT_MAX > INT_MAX, then (int) UINT_MAX
is implementation defined and needn't be -1.
so (int)((UINT_MAX+1)-2)==(int)UINT_MAX-1  ==-2
...
so (int)((UINT_MAX+1)-j)==(int)UINT_MAX-j+1==-j

Can i say if i have
unsigned  k=0;
that  for every j int or unsigned in [0, INT_MAX]
(int)(k-j)==-j ?
because
(int)(k-j)==(int)(0-j)==-j

No.
 
T

Tim Rentsch

Barry Schwarz said:
Hi all,

I'm using RedHat Enterprise Linux 4 and gcc version 3.4.6. It is my
understanding that unsigned int can only represent positive numbers,
i.e. values 0 or larger. However, why is it that the code below works?

unsigned int i;
i = -5;
printf("%d\n", i);

Since %d requires the corresponding argument to be an int and you
passed printf and unsigned int, you have caused printf to invoke
undefined behavior. [snip]

I feel obliged to point out that there are two schools of thought
on this question. Some people think passing an unsigned int
argument for a %d specifier /always/ results in undefined behavior.
Other people think passing an unsigned int argument for a %d
specifier results in undefined behavior /only if/ the value of the
unsigned int is greater than INT_MAX (ie, the same rule as the rule
for variadic functions). The text in the Standard itself can be
argued either way. I don't want to re-ignite debate on the issue,
but I do think it's reasonable to ask that the opposing viewpoint
be acknowledged, since there is not currently a consensus.
 
T

Tim Rentsch

Mark Bluemel said:
That's true.


At this point, the signed value -5 is assigned into an unsigned value.
The standard specifies the rules. I don't recall the details off-hand
and am too lazy to look it up, but simple assignment of the binary
value representing -5 seems reasonable.


You just lied to printf. You told it you would give it a signed number
and you passed an unsigned one.

Once more I'd like to point out there are two schools of
thought on this question. Please see my other response in
this thread.
Given that the unsigned int contains the same binary value as a signed
int containing -5, what would you expect printf to do?

This is not guaranteed to be true, it just happens to be
true in the particular implementation he is running.
Your question is based on a misapprehension.

In fact, two misapprehensions, but neither one was explained
very well. The same behavior would have resulted if this
printf had been done instead:

printf("%d\n", (int)i);

which unscores why talking about signed/unsigned arguments
to printf isn't very helpful.
 

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

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top