Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > return -1 using size_t???

Reply
Thread Tools

return -1 using size_t???

 
 
Robert Hayes
Guest
Posts: n/a
 
      02-11-2012
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,
 
Reply With Quote
 
 
 
 
Jeffrey R
Guest
Posts: n/a
 
      02-11-2012
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!
 
Reply With Quote
 
 
 
 
Shao Miller
Guest
Posts: n/a
 
      02-11-2012
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");
 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      02-11-2012
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
http://www.velocityreviews.com/forums/(E-Mail Removed)d
 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      02-11-2012
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
(E-Mail Removed)d
 
Reply With Quote
 
Robert Hayes
Guest
Posts: n/a
 
      02-11-2012
On Feb 11, 2:07*pm, Eric Sosman <(E-Mail Removed)> 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
> (E-Mail Removed)



Thank you for the clear explanation. I will not use a size_t to hold
a negative number.
 
Reply With Quote
 
Malcolm McLean
Guest
Posts: n/a
 
      02-11-2012
On Feb 11, 8:42*pm, Robert Hayes <(E-Mail Removed)> 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
 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      02-11-2012
On 2/11/2012 3:40 PM, Devil with the China Blue Dress wrote:
> In article<(E-Mail Removed)>,
> Robert Hayes<(E-Mail Removed)> 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
(E-Mail Removed)d
 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      02-11-2012
On 2/11/2012 5:11 PM, Devil with the China Blue Dress wrote:
> In article<jh6oh8$i77$(E-Mail Removed)>,
> Eric Sosman<(E-Mail Removed)> wrote:
>
>> On 2/11/2012 3:40 PM, Devil with the China Blue Dress wrote:
>>> In
>>> article<(E-Mail Removed)>,
>>> Robert Hayes<(E-Mail Removed)> 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
(E-Mail Removed)d
 
Reply With Quote
 
Jeffrey R
Guest
Posts: n/a
 
      02-11-2012
On Sat, 11 Feb 2012 12:42:30 -0800, Robert Hayes wrote:

> On Feb 11, 2:07*pm, Eric Sosman <(E-Mail Removed)> 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
>> (E-Mail Removed)

>
>
> 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.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
what value does lack of return or empty "return;" return Greenhorn C Programming 15 03-06-2005 08:19 PM
difference between return &*i and return i; Ganesh Gella C++ 4 11-12-2004 04:28 PM
getting return value from function without return statement. Seong-Kook Shin C Programming 1 06-18-2004 08:19 AM
How do I return a return-code from main? wl Java 2 03-05-2004 05:15 PM
Return a return value from Perl to Javascript PvdK Perl 0 07-24-2003 09:20 AM



Advertisments