Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   return -1 using size_t??? (http://www.velocityreviews.com/forums/t868206-return-1-using-size_t.html)

Robert Hayes 02-11-2012 07:21 PM

return -1 using size_t???
 
I have read that size_t can hold an unsigned int. I have been playing
with using size_t as a return value and I am not sure I should. I
wrote the following code to demonstrate the issue:

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

static size_t test(size_t test2) {
size_t a;
a = test2;
return a;
}

int main(int argc, char **argv) {
size_t b,c;
b = -1;
c = test(b);
if (c == -1)
printf("here\n");
else
printf("there\n");

printf("c = %zu\n",c);
return 0;
}

When b is -1 I see:
here
c = 18446744073709551615

When b is 3 I see:
there
c = 3

While I realize using an unsigned int to store a negative number is
not proper, why does it sort of work? By sort of work I mean the
comparison works but the printf doesn't. However if I change the
printf("c = %zu\n",c); to printf("c = %d\n",c) then when b is -1 I see
here and c = -1.

So should I use a size_t to hold -1? If not why does the comparison
work? I am using Ubuntu Lucid.

Thanks,

Jeffrey R 02-11-2012 07:58 PM

Re: return -1 using size_t???
 
On Sat, 11 Feb 2012 11:21:23 -0800, Robert Hayes wrote:

> I have read that size_t can hold an unsigned int. I have been playing
> with using size_t as a return value and I am not sure I should. I wrote
> the following code to demonstrate the issue:
>
> #include <stdio.h>
> #include <stdlib.h>
>
> static size_t test(size_t test2) {
> size_t a;
> a = test2;
> return a;
> }
>
> int main(int argc, char **argv) {
> size_t b,c;
> b = -1;
> c = test(b);
> if (c == -1)
> printf("here\n");
> else
> printf("there\n");
>
> printf("c = %zu\n",c);
> return 0;
> }
>
> When b is -1 I see:
> here
> c = 18446744073709551615
>
> When b is 3 I see:
> there
> c = 3
>
> While I realize using an unsigned int to store a negative number is not
> proper, why does it sort of work? By sort of work I mean the comparison
> works but the printf doesn't. However if I change the printf("c =
> %zu\n",c); to printf("c = %d\n",c) then when b is -1 I see here and c =
> -1.
>
> So should I use a size_t to hold -1? If not why does the comparison
> work? I am using Ubuntu Lucid.
>
> Thanks,


Assigning -1 into a size_t is an Undefined Behavior. Anything can happen,
be glad it didn't trash your hard disk!

Shao Miller 02-11-2012 08:00 PM

Re: return -1 using size_t???
 
On 2/11/2012 14:21, Robert Hayes wrote:
> I have read that size_t can hold an unsigned int. I have been playing
> with using size_t as a return value and I am not sure I should. I
> wrote the following code to demonstrate the issue:
>
> #include<stdio.h>
> #include<stdlib.h>
>
> static size_t test(size_t test2) {
> size_t a;
> a = test2;
> return a;
> }
>
> int main(int argc, char **argv) {
> size_t b,c;
> b = -1;
> c = test(b);
> if (c == -1)
> printf("here\n");
> else
> printf("there\n");
>
> printf("c = %zu\n",c);
> return 0;
> }
>
> When b is -1 I see:
> here
> c = 18446744073709551615
>
> When b is 3 I see:
> there
> c = 3
>
> While I realize using an unsigned int to store a negative number is
> not proper, why does it sort of work? By sort of work I mean the
> comparison works but the printf doesn't. However if I change the
> printf("c = %zu\n",c); to printf("c = %d\n",c) then when b is -1 I see
> here and c = -1.
>
> So should I use a size_t to hold -1? If not why does the comparison
> work? I am using Ubuntu Lucid.


When the value '-1' is converted to a 'size_t' on your platform, it'll
yield the value '18446744073709551615', which is the maximum value
representable with 64 value bits.

In your comparison before "here," the '-1' is promoted to a 'size_t'
value for the comparison. So your comparison is actually:

if (c == 18446744073709551615)
printf("here\n");

Eric Sosman 02-11-2012 08:07 PM

Re: return -1 using size_t???
 
On 2/11/2012 2:21 PM, Robert Hayes wrote:
> I have read that size_t can hold an unsigned int. I have been playing
> with using size_t as a return value and I am not sure I should. I
> wrote the following code to demonstrate the issue:
>
> #include<stdio.h>
> #include<stdlib.h>
>
> static size_t test(size_t test2) {
> size_t a;
> a = test2;
> return a;
> }
>
> int main(int argc, char **argv) {
> size_t b,c;
> b = -1;


As you note, `b' is an unsigned integer. Arithmetic on unsigned
integer is modular ("clock arithmetic"), so adding 1 to the type's
maximum value wraps around to zero. Also, subtracting 1 from the
types minimum value (zero) wraps around to the maximum value. And
that's what happens here: Converting -1 to an unsigned type produces
the type's maximum value. In your case, it appears that size_t is
a 64-bit unsigned type, so -1 becomes 0xFFFFFFFFFFFFFFFF, the very
large value you've printed in decimal form.

> c = test(b);
> if (c == -1)


This compares the size_t value `c' to the (signed) int value -1.
When you compare dissimilar types, C converts the values to a common
type and compares the converted values. There's a bunch of rules about
what converts to what in which circumstances; in this case, the int
value is converted to size_t and compared with `c'. Converting -1
to size_t works here just as it did above, and yields that very large
number -- which is, of course, equal to the very large number in `c'.

> printf("here\n");
> else
> printf("there\n");
>
> printf("c = %zu\n",c);
> return 0;
> }
>
> When b is -1 I see:
> here
> c = 18446744073709551615
>
> When b is 3 I see:
> there
> c = 3
>
> While I realize using an unsigned int to store a negative number is
> not proper, why does it sort of work? By sort of work I mean the
> comparison works but the printf doesn't.


Once you take the conversions into account, I think you'll agree
that both constructs "work."

> However if I change the
> printf("c = %zu\n",c); to printf("c = %d\n",c) then when b is -1 I see
> here and c = -1.


Happenstance. The "%d" conversion specifier must match a (signed)
int argument, but you're feeding it a size_t. Since the argument is
not of the expected type, you get the dreaded Undefined Behavior: C no
longer guarantees anything about what your program will do. (By the
way, gcc will warn you about mismatches of this kind if you crank up
its warning levels a bit: "-Wall -W -std=c99" is a reasonable start,
and you can get it to be even more picky if you wish.)

What (probably) happened is that "%d" looked at (probably) one
half or the other of the 64-bit size_t value, saw that the half had
all bits set, and interpreted that as the int value minus one. What
happened to the other half remains shrouded in mystery: Maybe it
just sat in a CPU register and was ignored, maybe it hung around in
a stack slot ready to confuse the next conversion, maybe it donated
your bank balance to the Greek bailout fund.

> So should I use a size_t to hold -1? If not why does the comparison
> work? I am using Ubuntu Lucid.


size_t cannot hold -1, nor any other negative value. It can,
however, hold the "wrapped around" value that results from converting
-1 to size_t; this value is large and positive. You can, if you
like, impute some special meaning to that large value, just as you
might treat zero as special, or -42 (in a signed type). Just don't
expect `(size_t)-1' to be negative, because it ain't.

size_t is also unable to hold extremely large positive values:
There is a maximum possible value for a size_t. If you try to go
above the maximum, the too-large number wraps around and becomes a
small non-negative value.

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

Eric Sosman 02-11-2012 08:11 PM

Re: return -1 using size_t???
 
On 2/11/2012 2:58 PM, Jeffrey R wrote:
>
> Assigning -1 into a size_t is an Undefined Behavior. Anything can happen,
> be glad it didn't trash your hard disk!


Nonsense. The behavior is implementation-defined, not undefined.
(The implementation-defined aspect is the maximum value of the size_t
type; it can be as small as 65535 or as large as, as, well, as large
as Very Large Indeed.)

The conversion will not trash a disk, nor cause butterscotch
pudding to ooze from your keyboard, nor make demons fly out of your
nose. It will yield the largest value a size_t can hold, period.

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

Robert Hayes 02-11-2012 08:42 PM

Re: return -1 using size_t???
 
On Feb 11, 2:07*pm, Eric Sosman <esos...@ieee-dot-org.invalid> wrote:
> On 2/11/2012 2:21 PM, Robert wrote:
> > I have read that size_t can hold an unsigned int. *I have been playing
> > with using size_t as a return value and I am not sure I should. *I
> > wrote the following code to demonstrate the issue:

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

>
> > static size_t test(size_t test2) {
> > size_t a;
> > a = test2;
> > return a;
> > }

>
> > int main(int argc, char **argv) {
> > size_t b,c;
> > b = -1;

>
> * * *As you note, `b' is an unsigned integer. *Arithmetic on unsigned
> integer is modular ("clock arithmetic"), so adding 1 to the type's
> maximum value wraps around to zero. *Also, subtracting 1 from the
> types minimum value (zero) wraps around to the maximum value. *And
> that's what happens here: Converting -1 to an unsigned type produces
> the type's maximum value. *In your case, it appears that size_t is
> a 64-bit unsigned type, so -1 becomes 0xFFFFFFFFFFFFFFFF, the very
> large value you've printed in decimal form.
>
> > c = test(b);
> > if (c == -1)

>
> * * *This compares the size_t value `c' to the (signed) int value -1.
> When you compare dissimilar types, C converts the values to a common
> type and compares the converted values. *There's a bunch of rules about
> what converts to what in which circumstances; in this case, the int
> value is converted to size_t and compared with `c'. *Converting -1
> to size_t works here just as it did above, and yields that very large
> number -- which is, of course, equal to the very large number in `c'.
> > * *printf("here\n");
> > else
> > * *printf("there\n");

>
> > printf("c = %zu\n",c);
> > return 0;
> > }

>
> > When b is -1 I see:
> > here
> > c = 18446744073709551615

>
> > When b is 3 I see:
> > there
> > c = 3

>
> > While I realize using an unsigned int to store a negative number is
> > not proper, why does it sort of work? *By sort of work I mean the
> > comparison works but the printf doesn't.

>
> * * *Once you take the conversions into account, I think you'll agree
> that both constructs "work."
>
> > However if I change the
> > printf("c = %zu\n",c); to printf("c = %d\n",c) then when b is -1 I see
> > here and c = -1.

>
> * * *Happenstance. *The "%d" conversion specifier must match a (signed)
> int argument, but you're feeding it a size_t. *Since the argument is
> not of the expected type, you get the dreaded Undefined Behavior: C no
> longer guarantees anything about what your program will do. *(By the
> way, gcc will warn you about mismatches of this kind if you crank up
> its warning levels a bit: "-Wall -W -std=c99" is a reasonable start,
> and you can get it to be even more picky if you wish.)
>
> * * *What (probably) happened is that "%d" looked at (probably) one
> half or the other of the 64-bit size_t value, saw that the half had
> all bits set, and interpreted that as the int value minus one. *What
> happened to the other half remains shrouded in mystery: Maybe it
> just sat in a CPU register and was ignored, maybe it hung around in
> a stack slot ready to confuse the next conversion, maybe it donated
> your bank balance to the Greek bailout fund.
>
> > So should I use a size_t to hold -1? *If not why does the comparison
> > work? *I am using Ubuntu Lucid.

>
> * * *size_t cannot hold -1, nor any other negative value. *It can,
> however, hold the "wrapped around" value that results from converting
> -1 to size_t; this value is large and positive. *You can, if you
> like, impute some special meaning to that large value, just as you
> might treat zero as special, or -42 (in a signed type). *Just don't
> expect `(size_t)-1' to be negative, because it ain't.
>
> * * *size_t is also unable to hold extremely large positive values:
> There is a maximum possible value for a size_t. *If you try to go
> above the maximum, the too-large number wraps around and becomes a
> small non-negative value.
>
> --
> Eric Sosman
> esos...@ieee-dot-org.invalid



Thank you for the clear explanation. I will not use a size_t to hold
a negative number.

Malcolm McLean 02-11-2012 09:19 PM

Re: return -1 using size_t???
 
On Feb 11, 8:42*pm, Robert Hayes <rhye...@gmail.com> wrote:
>
> Thank you for the clear explanation. *I will not use a size_t to hold
> a negative number.- Hide quoted text -
>

There's an example of a size_t holding a negative number on the thread
about stripping right spaces.


--
Vist my website. MPI tutorial
http://www.malcolm.mclean.site11.com/www

Eric Sosman 02-11-2012 10:02 PM

Re: return -1 using size_t???
 
On 2/11/2012 3:40 PM, Devil with the China Blue Dress wrote:
> In article<8c1eef8c-2ba4-441e-aa86-36486b56a261@n12g2000yqb.googlegroups.com>,
> Robert Hayes<rhyes80@gmail.com> wrote:
>
>> While I realize using an unsigned int to store a negative number is
>> not proper, why does it sort of work? By sort of work I mean the

>
> On a twos complement CPU, [...]


On no C implementation anywhere does size_t use two's complement.
Nor ones' complement, nor signed magnitude.

> Addition and subtraction will yield the same bit patterns with either
> interpretation. If the most significant bits are equal, comparison will be the
> same.


C's comparison and equality operators use values, not bit patterns.
Here's (slightly non-portable) proof:

#include <string.h>
#include <math.h>
#include <assert.h>
...
float f = NAN;
float g = NAN;
assert(memcmp(&f, &g, sizeof f) == 0); // identical bits
assert(f != g); // unequal values

Here's another proof (I think this one's portable):

struct {
unsigned int p : 1;
unsigned int q : 15;
} s;
s.p = 1;
s.q = 1;
assert(s.p == s.q); // different bits, equal values

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

Eric Sosman 02-11-2012 10:21 PM

Re: return -1 using size_t???
 
On 2/11/2012 5:11 PM, Devil with the China Blue Dress wrote:
> In article<jh6oh8$i77$1@dont-email.me>,
> Eric Sosman<esosman@ieee-dot-org.invalid> wrote:
>
>> On 2/11/2012 3:40 PM, Devil with the China Blue Dress wrote:
>>> In
>>> article<8c1eef8c-2ba4-441e-aa86-36486b56a261@n12g2000yqb.googlegroups.com>,
>>> Robert Hayes<rhyes80@gmail.com> wrote:
>>>
>>>> While I realize using an unsigned int to store a negative number is
>>>> not proper, why does it sort of work? By sort of work I mean the
>>>
>>> On a twos complement CPU, [...]

>
> And you snipped that all references were to integers


The question was about *unsigned* integers. *Unsigned* integers
in C never use complement represention.

>> Here's another proof (I think this one's portable):
>>
>> struct {
>> unsigned int p : 1;
>> unsigned int q : 15;
>> } s;
>> s.p = 1;
>> s.q = 1;
>> assert(s.p == s.q); // different bits, equal values

>
> The bit pattern of s.p would be 0...1 and s.q would be 0...000000000000001
> widenned to the number of bits in an unsigned int.


The bit pattern of s.p is `1', period. The bit pattern of
s.q is `000000000000001', period. These bit patterns necessarily
disagree, since they're not even the same size.

I've made two points about your post: First, talking about
representation schemes for negative numbers is silly when the
type in question is unsigned. Second, suggesting that comparison
relies on bit patterns without regard to types is not merely
silly, but wrong. (I could also have taken issue with the
misstatement about "most significant bits," but enough's enough.)

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

Jeffrey R 02-11-2012 10:25 PM

Re: return -1 using size_t???
 
On Sat, 11 Feb 2012 12:42:30 -0800, Robert Hayes wrote:

> On Feb 11, 2:07*pm, Eric Sosman <esos...@ieee-dot-org.invalid> wrote:
>> On 2/11/2012 2:21 PM, Robert wrote:
>> > I have read that size_t can hold an unsigned int. *I have been
>> > playing with using size_t as a return value and I am not sure I
>> > should. *I wrote the following code to demonstrate the issue:

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

>>
>> > static size_t test(size_t test2) {
>> > size_t a;
>> > a = test2;
>> > return a;
>> > }

>>
>> > int main(int argc, char **argv) {
>> > size_t b,c;
>> > b = -1;

>>
>> * * *As you note, `b' is an unsigned integer. *Arithmetic on
>> * * *unsigned
>> integer is modular ("clock arithmetic"), so adding 1 to the type's
>> maximum value wraps around to zero. *Also, subtracting 1 from the types
>> minimum value (zero) wraps around to the maximum value. *And that's
>> what happens here: Converting -1 to an unsigned type produces the
>> type's maximum value. *In your case, it appears that size_t is a 64-bit
>> unsigned type, so -1 becomes 0xFFFFFFFFFFFFFFFF, the very large value
>> you've printed in decimal form.
>>
>> > c = test(b);
>> > if (c == -1)

>>
>> * * *This compares the size_t value `c' to the (signed) int value
>> * * *-1.
>> When you compare dissimilar types, C converts the values to a common
>> type and compares the converted values. *There's a bunch of rules about
>> what converts to what in which circumstances; in this case, the int
>> value is converted to size_t and compared with `c'. *Converting -1 to
>> size_t works here just as it did above, and yields that very large
>> number -- which is, of course, equal to the very large number in `c'.
>> > * *printf("here\n");
>> > else
>> > * *printf("there\n");

>>
>> > printf("c = %zu\n",c);
>> > return 0;
>> > }

>>
>> > When b is -1 I see:
>> > here
>> > c = 18446744073709551615

>>
>> > When b is 3 I see:
>> > there
>> > c = 3

>>
>> > While I realize using an unsigned int to store a negative number is
>> > not proper, why does it sort of work? *By sort of work I mean the
>> > comparison works but the printf doesn't.

>>
>> * * *Once you take the conversions into account, I think you'll
>> * * *agree
>> that both constructs "work."
>>
>> > However if I change the
>> > printf("c = %zu\n",c); to printf("c = %d\n",c) then when b is -1 I
>> > see here and c = -1.

>>
>> * * *Happenstance. *The "%d" conversion specifier must match a
>> * * *(signed)
>> int argument, but you're feeding it a size_t. *Since the argument is
>> not of the expected type, you get the dreaded Undefined Behavior: C no
>> longer guarantees anything about what your program will do. *(By the
>> way, gcc will warn you about mismatches of this kind if you crank up
>> its warning levels a bit: "-Wall -W -std=c99" is a reasonable start,
>> and you can get it to be even more picky if you wish.)
>>
>> * * *What (probably) happened is that "%d" looked at (probably) one
>> half or the other of the 64-bit size_t value, saw that the half had all
>> bits set, and interpreted that as the int value minus one. *What
>> happened to the other half remains shrouded in mystery: Maybe it just
>> sat in a CPU register and was ignored, maybe it hung around in a stack
>> slot ready to confuse the next conversion, maybe it donated your bank
>> balance to the Greek bailout fund.
>>
>> > So should I use a size_t to hold -1? *If not why does the comparison
>> > work? *I am using Ubuntu Lucid.

>>
>> * * *size_t cannot hold -1, nor any other negative value. *It can,
>> however, hold the "wrapped around" value that results from converting
>> -1 to size_t; this value is large and positive. *You can, if you like,
>> impute some special meaning to that large value, just as you might
>> treat zero as special, or -42 (in a signed type). *Just don't expect
>> `(size_t)-1' to be negative, because it ain't.
>>
>> * * *size_t is also unable to hold extremely large positive values:
>> There is a maximum possible value for a size_t. *If you try to go above
>> the maximum, the too-large number wraps around and becomes a small
>> non-negative value.
>>
>> --
>> Eric Sosman
>> esos...@ieee-dot-org.invalid

>
>
> Thank you for the clear explanation. I will not use a size_t to hold a
> negative number.


This explanation may seem clear but it is also WRONG!

It is assuming that the CPU is 2-s compliment.

In many common cases eg on x86, behavior will be as Eric Sossman
describes. However, this is not guaranteed and not portable. On other
platforms it could trigger an overflow signal from the ALU or lead to a
Trap Representation. In fact, Undefined Behavior means that anything
could happen! Including (in theory) reformatting your hard disk.

A size_t is an UN-SIGNED type, trying to store a negative number in it is
a programmer error generating an undefined behavior.


All times are GMT. The time now is 08:22 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.