Google Grupper understøtter ikke længere nye Usenet-opslag eller -abonnementer. Tidligere indhold er fortsat synligt.

Usage of unsigned integers

69 visninger
Gå til det første ulæste opslag

Sungbom Kim

ulæst,
24. nov. 2001, 06.06.4924.11.2001
til
Can you suggest recommended/discouraged usage of unsigned integers?

I know that unsigned integers are...
* very good for dealing with bit patterns or bit arrays
* NOT recommended for just gaining one more bit of storage
* NOT recommended for ensuring positiveness

Any others?

How about using unsigned integers for quantities that just don't
go below zero, for example months(1..12), days of month(1..31),
days of week(0..6 or 1..7), etc. in calendar programs?

--
Sungbom Kim <musi...@bawi.org>


[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

Francis Glassborow

ulæst,
24. nov. 2001, 19.30.5424.11.2001
til
In article <3BFEEAE8...@bawi.org>, Sungbom Kim <musi...@bawi.org>
writes

>How about using unsigned integers for quantities that just don't
>go below zero, for example months(1..12), days of month(1..31),
>days of week(0..6 or 1..7), etc. in calendar programs?

I would far prefer to see such entities represented by UDTs. A class
does not just provide a mechanism for hiding data, it allows the
designer to determine what is appropriate behaviour. A month is not any
kind of int (you cannot multiply or divide months representing elements
of a calendar, you can add/subtract an integer value to a month but even
that requires special processing to handle going outside the range)

I think that fundamental types are often abused in C++ by being made to
do things for which they are not really good matches. Note that it is
easier to deal with range problems for the examples you give if the
internal representation is signed.


--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

Pete Becker

ulæst,
25. nov. 2001, 08.47.3325.11.2001
til
Francis Glassborow wrote:
>
> In article <3BFEEAE8...@bawi.org>, Sungbom Kim <musi...@bawi.org>
> writes
> >How about using unsigned integers for quantities that just don't
> >go below zero, for example months(1..12), days of month(1..31),
> >days of week(0..6 or 1..7), etc. in calendar programs?
>
> I would far prefer to see such entities represented by UDTs. A class
> does not just provide a mechanism for hiding data, it allows the
> designer to determine what is appropriate behaviour. A month is not any
> kind of int (you cannot multiply or divide months representing elements
> of a calendar, you can add/subtract an integer value to a month but even
> that requires special processing to handle going outside the range)
>

You also use the month number as an index into an array of ints to get
number of days in a month, or the number of days from the beginning of a
year to the beginning of that month. The day of the week for a
particular date is the day of the week of the first day of the year plus
the number of days from the first day of the year to that date, mod 7.
With all this integer math being done, using a UDT can be disastrous.
You either have to write explicit conversions which obfuscate the code
or you provide implicit conversions which lead to intractable
ambiguities. It's rarely a good idea to write UDTs that act like
integral types.

--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

Terje Slettebø

ulæst,
25. nov. 2001, 08.49.0825.11.2001
til
"Sungbom Kim" <musi...@bawi.org> wrote in message
news:3BFEEAE8...@bawi.org...

> Can you suggest recommended/discouraged usage of unsigned integers?
>
> I know that unsigned integers are...
> * very good for dealing with bit patterns or bit arrays
> * NOT recommended for just gaining one more bit of storage
> * NOT recommended for ensuring positiveness

Well, you can of course use them to get one more bit of storage. There's
nothing wrong with that. It should be ok to use it to ensure positiveness,
too, why not?

I find unsigned numbers very useful, actually. I tend to use it to put
semantics into my program (similar to using const), that is enforced by the
program. It's simple: When you use an unsigned number, you _know_ it can't
be negative (thus, you _can_ ensure positiveness).

Since it can't be negative, you may also avoid checks for negativeness, like
this:

void f(int i) // Signed
{
if(i>=0 && i<10)
...
}

void f(unsigned int i) // Unsigned
{
if(i<10)
...
}

Thus, you both communicate that the number is not negative (adding
semantics), and this is also enforced by the program, so you can avoid an
extra check. :) Which means more efficiency.

This is actually so common in my program, using unsigned variables, if the
values are unsigned, that I have the following typedef's in a common
header-file, to cut down the typing, when using unsigned variables:

typedef unsigned int uint;
typedef unsigned short ushort;
typedef unsigned char uchar;


> Any others?
>
> How about using unsigned integers for quantities that just don't
> go below zero, for example months(1..12), days of month(1..31),
> days of week(0..6 or 1..7), etc. in calendar programs?

You can do that. That's an example of values that can't be negative, so that
property would be enforced by the program, without explicit checks, as shown
above.


Regards,

Terje Slettebø

tslettebo at chello dot no.

James Rogers

ulæst,
25. nov. 2001, 21.59.2825.11.2001
til
Pete Becker wrote:
>
> You also use the month number as an index into an array of ints to get
> number of days in a month, or the number of days from the beginning of a
> year to the beginning of that month.

The problem here is clearly efficiency.

Using a month number to index an array requires either space or
execution inefficiency. Since all C++ arrays begin indexing at 0 you
must either calculate the offset from the month number or provide an
extra array element, effectively wasting the first element.

Whether or not you use unsigned integers you must still check math
operations for out of bounds results. For instance, when counting
months the math should be modular. That is to say that the month
following month 12 is month 1. Unsigned integers simply do not help
with this problem. They provide no benefit over signed integers.

If C++ were to provide the ability to define a modular integer type
there would still be some problems. If the type could be defined as

typedef mod <12> month;

The result would be a type with a range of 0 through 11. There would
still be some mapping ineffiencies with the desired range of 1
through 12. Such a type, however, might have the modular nature
of its math pre-defined. This would be a useful feature. Note that
the modular integer type would map efficiently to array indices.

Jim Rogers
Colorado Springs, Colorado USA

Dave Harris

ulæst,
26. nov. 2001, 05.23.4726.11.2001
til
musi...@bawi.org (Sungbom Kim) wrote (abridged):

> How about using unsigned integers for quantities that just don't
> go below zero, for example months(1..12), days of month(1..31),
> days of week(0..6 or 1..7), etc. in calendar programs?

That would be too risky for me. I would be concerned about code like:

if (day1 - day2 < 7)

behaving differently to:

if (day1 < day2 + 7)

Intuitively these say the same thing; we just added day2 to both sides of
the comparison. With unsigned maths they are different. Eg if day1=3 and
day2=2, then the first evaluates to UINT_MAX < 7, which is false, and the
second is 3 < 9, which is true.

Unsigned integers have a massive discontiguity at 0. It is too close to
the range of "normal" numbers for comfort. Signed integers move the
discontiguity to INT_MAX where it causes fewer problems.

Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
bran...@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."

Francis Glassborow

ulæst,
26. nov. 2001, 10.51.5926.11.2001
til
In article <3C005609...@acm.org>, Pete Becker <peteb...@acm.org>
writes

>You also use the month number as an index into an array of ints to get
>number of days in a month, or the number of days from the beginning of a
>year to the beginning of that month. The day of the week for a
>particular date is the day of the week of the first day of the year plus
>the number of days from the first day of the year to that date, mod 7.
>With all this integer math being done, using a UDT can be disastrous.
>You either have to write explicit conversions which obfuscate the code
>or you provide implicit conversions which lead to intractable
>ambiguities. It's rarely a good idea to write UDTs that act like
>integral types.

But I do not think that months (i.e. the twelve calendar months do
behave like integers. And all that other stuff deserves to be
encapsulated.


--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Sungbom Kim

ulæst,
26. nov. 2001, 10.53.4826.11.2001
til
Terje Slettebø wrote:
>
> "Sungbom Kim" <musi...@bawi.org> wrote in message
> news:3BFEEAE8...@bawi.org...
> > Can you suggest recommended/discouraged usage of unsigned integers?
> >
> > I know that unsigned integers are...
> > * very good for dealing with bit patterns or bit arrays
> > * NOT recommended for just gaining one more bit of storage
> > * NOT recommended for ensuring positiveness
>
> Well, you can of course use them to get one more bit of storage. There's
> nothing wrong with that. It should be ok to use it to ensure positiveness,
> too, why not?

Bjarne Stroustrup says in The C++ Programming Language, 4.4:

The <unsigned> integer types are ideal for uses that treat storage
as a bit array. Using an <unsigned> instead of an <int> to gain
one more bit to represent positive integers is almost never a good
idea. Attempts to ensure that some values are positive by declaring
variables <unsigned> will typically be defeated by the implicit
conversion rules.

Why would he have said so?

> I find unsigned numbers very useful, actually. I tend to use it to put
> semantics into my program (similar to using const), that is enforced by the
> program. It's simple: When you use an unsigned number, you _know_ it can't
> be negative (thus, you _can_ ensure positiveness).

You also have to mind that variables of unsigned integral types are
just *interpreted* as non-negative values (via modulo operation);
nothing prevents you from assigning them negative numbers or making
them pass below zero:

unsigned a = -1; // a interpreted as UINT_MAX
unsigned b = 2; b -= 3; // b interpreted as UINT_MAX

So relying on unsignedness of unsigned integers can be dangerous.

To express reliable semantics, you'll have to employ a range-checked
number class.

> Since it can't be negative, you may also avoid checks for negativeness, like
> this:
>
> void f(int i) // Signed
> {
> if(i>=0 && i<10)
> ...
> }
>
> void f(unsigned int i) // Unsigned
> {
> if(i<10)
> ...
> }
>
> Thus, you both communicate that the number is not negative (adding
> semantics), and this is also enforced by the program, so you can avoid an
> extra check. :) Which means more efficiency.

For small integers it is okay, but for large ones I'm afraid there is
a possibility that 'big' negative numbers might wrap around to be
interpreted positive and small enough. For example, (unsigned)-30000
is evaluated less than (unsigned)40000 in a 16-bit environment. In
such a case, what would be the answer? A larger unsigned integer?

And there is also a possibility that unsigned integers that have
'semantically' negative values might be evaluated greater than
most positive values.

bool big_enough(unsigned x) { return x >= 100; }
unsigned x = 10;
// x is decremented below zero somehow...
if (big_enough(x)) { /* ... */ }

Because of these kinds of surprises that unsigned integers give,
I tend to prefer signed integers for quantitative values (which
can be operands of arithmetic operations).

> This is actually so common in my program, using unsigned variables, if the
> values are unsigned, that I have the following typedef's in a common
> header-file, to cut down the typing, when using unsigned variables:
>
> typedef unsigned int uint;
> typedef unsigned short ushort;
> typedef unsigned char uchar;

Yes, they are so common indeed. What do you think of providing those
in a standard header file, for convenience for and consistency among
programmers?

--
Sungbom Kim <musi...@bawi.org>

Michiel Salters

ulæst,
26. nov. 2001, 11.07.1226.11.2001
til
In article <3C005609...@acm.org>, Pete Becker says...

>
>Francis Glassborow wrote:
>>
>> In article <3BFEEAE8...@bawi.org>, Sungbom Kim <musi...@bawi.org>
>> writes
>> >How about using unsigned integers for quantities that just don't
>> >go below zero, for example months(1..12), days of month(1..31),
>> >days of week(0..6 or 1..7), etc. in calendar programs?
>>
>> I would far prefer to see such entities represented by UDTs. A class
>> does not just provide a mechanism for hiding data, it allows the
>> designer to determine what is appropriate behaviour. A month is not any
>> kind of int (you cannot multiply or divide months representing elements
>> of a calendar, you can add/subtract an integer value to a month but even
>> that requires special processing to handle going outside the range)
>>
>
>You also use the month number as an index into an array of ints to get
>number of days in a month,
[SNIP]
Using INT_MAX-1 as an array index is about as bad as using -1. So I don't
believe in array indexing as a reason to use unsigned ints.
( Unsigned chars typically can be used, though. )

Regards,

--
Michiel Salters
Consultant Technical Software Engineering
CMG Trade, Transport & Industry
Michiel...@cmg.nl

Francis Glassborow

ulæst,
26. nov. 2001, 11.07.3626.11.2001
til
In article <3C01148D...@worldnet.att.net>, James Rogers
<jimmaure...@worldnet.att.net> writes

>The result would be a type with a range of 0 through 11. There would
>still be some mapping ineffiencies with the desired range of 1
>through 12. Such a type, however, might have the modular nature
>of its math pre-defined. This would be a useful feature. Note that
>the modular integer type would map efficiently to array indices.

Indeed modular integers are so pervasive in the real world that I think
they make a good candidate for being a Standard template class:

template<unsigned int upper_bound>
class modular {
...
};

And implementing that should use the hoisting idiom to stop code bloat.

--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

ulæst,
26. nov. 2001, 11.17.2026.11.2001
til
Terje Slettebø <clcppm...@this.is.invalid> wrote in message
news:<SX_L7.4334$Sa4.5...@news01.chello.no>...

> "Sungbom Kim" <musi...@bawi.org> wrote in message
> news:3BFEEAE8...@bawi.org...
> > Can you suggest recommended/discouraged usage of unsigned integers?

> > I know that unsigned integers are...
> > * very good for dealing with bit patterns or bit arrays
> > * NOT recommended for just gaining one more bit of storage
> > * NOT recommended for ensuring positiveness

> Well, you can of course use them to get one more bit of storage.

But should you? If the design logic suggests signed integers, for
whatever reason, using unsigned just to gain one bit is probably short
sighted. It obfuscates, and if the range without that one bit wasn't
sufficient, you can be sure that even with the bit, it will be
insufficient very quickly.

> There's nothing wrong with that. It should be ok to use it to ensure
> positiveness, too, why not?

Because it doesn't work. An unsigned number is always positive. Even
when it was initialized with a negative number. This can potentially
hide errors.

> I find unsigned numbers very useful, actually. I tend to use it to
> put semantics into my program (similar to using const), that is
> enforced by the program. It's simple: When you use an unsigned
> number, you _know_ it can't be negative (thus, you _can_ ensure
> positiveness).

The problem is, you can know that the value you got isn't negative,
but you can't know that the caller didn't try to pass you a negative.

> Since it can't be negative, you may also avoid checks for
> negativeness, like this:

> void f(int i) // Signed
> {
> if(i>=0 && i<10)
> ...
> }

> void f(unsigned int i) // Unsigned
> {
> if(i<10)
> ...
> }

> Thus, you both communicate that the number is not negative (adding
> semantics), and this is also enforced by the program, so you can
> avoid an extra check. :) Which means more efficiency.

You have to communicate the range out of band anyway; why is it so
important to avoid the >= 0 comment, but not the < 10 comment? And I
would expect any decent compiler to generate the same code for your
two examples, so I don't see where the efficiency argument comes into
play.

> This is actually so common in my program, using unsigned variables,
> if the values are unsigned, that I have the following typedef's in a
> common header-file, to cut down the typing, when using unsigned
> variables:

> typedef unsigned int uint;
> typedef unsigned short ushort;
> typedef unsigned char uchar;

That's dangerous, but for a completely different reason. These names
seem so popular that a lot of libraries (Posix, for example) try and
define them. I avoid them like the plague, because of the risk of
name conflicts. (But this may be a hang-over from my C days. In C++,
I think that multiple typedef's of the same name are legal, as long as
they define the same types. And I've yet to see a library which
defined them differently than you do here.)

> > Any others?

> > How about using unsigned integers for quantities that just don't
> > go below zero, for example months(1..12), days of month(1..31),
> > days of week(0..6 or 1..7), etc. in calendar programs?

> You can do that. That's an example of values that can't be negative,
> so that property would be enforced by the program, without explicit
> checks, as shown above.

The problem is that the checking is worthless. Not only can a month
not be negative, it can't even be 0, nor > 12. As for a day in the
month, the maximum value depends on the month.

My own solution for such values is first to wrap them. The user can't
see or get at my internal representation of month, so he doesn't know
if it is int, unsigned or even std::string. Under the wraps, I tend
to use unsigned, but for a completely different reason ; depending on
the application, I may want to use some sort of packed representation,
and only unsigned's can be dependably used in bit fields.

--
James Kanze mailto:ka...@gabi-soft.de
Beratung in objektorientierer Datenverarbeitung --
-- Conseils en informatique orientée objet
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany, Tél.: +49 (0)69 19 86 27

David Bradley

ulæst,
26. nov. 2001, 16.54.1926.11.2001
til
James Kanze wrote:

> The problem is, you can know that the value you got isn't negative,
> but you can't know that the caller didn't try to pass you a negative.

You can't know but the caller should get a warning from the compiler
complaining about the passing of a signed to an unsigned. Isn't that
worth something? If I'm implementing a function and a negative number
makes no sense, doesn't it make more sense to let the compiler tell my
caller that he's doing something potentially bad, rather than waiting
for a runtime assert/error.

Terje Slettebø

ulæst,
26. nov. 2001, 19.59.4226.11.2001
til
"Sungbom Kim" <musi...@bawi.org> wrote in message
news:3C01A154...@bawi.org...

Hi.

> Terje Sletteb wrote:
> >
> > "Sungbom Kim" <musi...@bawi.org> wrote in message
> > news:3BFEEAE8...@bawi.org...
> > > Can you suggest recommended/discouraged usage of unsigned integers?
> > >
> > > I know that unsigned integers are...
> > > * very good for dealing with bit patterns or bit arrays
> > > * NOT recommended for just gaining one more bit of storage
> > > * NOT recommended for ensuring positiveness
> >
> > Well, you can of course use them to get one more bit of storage. There's
> > nothing wrong with that. It should be ok to use it to ensure
positiveness,
> > too, why not?
>
> Bjarne Stroustrup says in The C++ Programming Language, 4.4:
>
> The <unsigned> integer types are ideal for uses that treat storage
> as a bit array. Using an <unsigned> instead of an <int> to gain
> one more bit to represent positive integers is almost never a good
> idea. Attempts to ensure that some values are positive by declaring
> variables <unsigned> will typically be defeated by the implicit
> conversion rules.
>
> Why would he have said so?

I think it's important that when advice is given, not only the advice, but
also _why_ this is adviced, should be included. Scott Meyer's "Effective
C++" books are excellent at this. They explain the reason for the advice, so
you can assess, yourself, whether or not it applies to the situation at
hand.

I have also experience with assembly programming, so I know how signed and
unsigned are treated at that level.

There is nothing wrong with using an unsigned number, to gain one more bit
of storage. If others in the newsgroup disagrees, feel free to give reasons
for the opposite.

To take the example of char. Signed char gives the range -128 to 127.
Unsigned char gives 0 to 255. Not useful? I'd definitely think it's useful.
You just got twice as large positive range. The same goes for all the
integers.

If you used a signed char to represent an 8-bit char, it wouldn't fit. You
would only get half the range.

What about you, don't you think this is useful?

I think Bjarne Stroustrup gave the blanket advice, to warn against if people
used unsigned types to represent _signed_ values, and uses unsigned, just to
get one more bit of storage. If the numbers then happen to be negative, you
get the wrong values (since unsigned types can't represent negative values).

This is why I think he said that. If you use unsigned types to represent
values that can actually be negative, you get the wrong values.

If you represent unsigned values with unsigned integers, it's perfectly
safe. It's not just safe, it can be an advantage, because you specify a more
specific type (the way an UDT is a more specific type), and the program
enforces it.

The problem is if people take advice, without understanding why it's
adviced, it may be taken as advice even in areas it doesn't apply, and may
in fact be a disadvantage.


Regarding ensuring positiveness. I gave an example that demonstrates that
the positiveness is ensured ("if(i<10) ... // i>=0 && i<10 "). Thus, this is
a counter-example that it's possible.

Again, I think he gave the advice, if people try to ensure positiveness, in
the sense of a conversion. For that, it's no good, and I agree. Again, the
problem is that, at least in the short quote, here, little specific
explanation on _why_ it's adviced, is given.

As an example:

int i=-1;
unsigned int j=i; // No good as conversion; j will be 255, not 1.

However, again, if you know the values are positive, it's safe to use
unsigned types, and, like in the example with if(), above, it actually makes
it more efficient.

Besides, as mentioned, it documents that the value is always positive.


> > I find unsigned numbers very useful, actually. I tend to use it to put
> > semantics into my program (similar to using const), that is enforced by
the
> > program. It's simple: When you use an unsigned number, you _know_ it
can't
> > be negative (thus, you _can_ ensure positiveness).
>
> You also have to mind that variables of unsigned integral types are
> just *interpreted* as non-negative values (via modulo operation);

Yes, when you _convert_ from signed values.

What happens is that the bits are interpreted as unsigned, rather than
signed values, which gives a different result.

No operation is actually performed on the value. No modulo, or otherwise.
It's just the interpretation of the same bits, that changes, and therefore
you get a different value.


In use, unsigned variables behave just like signed variables, except they
can't be negative, so operations that would normally result in negative
values, like your example below, here, you get the wrong values.

Thus, regarding interpreting the numbers, that is the same way, for both
signed and unsigned numbers. Unsigned numbers aren't interpreted in any
special way. For an 8-bit number, for example, 255 and -1 are two
interpretations of the case when all bits are set. As you can see, they are
both interpretations of the same bit pattern. Unsigned or signed numbers
aren't treated in any special way.

In addition, the operations on numbers work the same way, whether they are
interpreted as signed or unsigned.


> nothing prevents you from assigning them negative numbers or making
> them pass below zero:

That's correct.

You would, however, usually get a warning from the compiler, if you try to
assign a signed value to an unsigned variable.

Regarding passing below zero, that's an underflow, for unsigned variables,
and overflows and underflows give no error, regardless if you're using
signed or unsigned variables. Unsigned variables are no different in this
respect.


If you mean, by ensuring positiveness, that you can't do:

unsigned int a=-1; // a won't be 1, but UINT_MAX (as you show in your
example)

then I agree with you.

But this was not what I meant, when I said you can ensure positiveness.

I was not talking about conversions. I was talking about that if you have an
unsigned type, it is _ensured_ that the number is positive. The simple
reason is that it can't be negative.

Whether a conversion from a signed, to an unsigned type, yield correct
values, is an entirely different matter. In this case, you have to ensure
that you're not initializing it with invalid values (negative values, in
this case).


> unsigned a = -1; // a interpreted as UINT_MAX
> unsigned b = 2; b -= 3; // b interpreted as UINT_MAX
>
> So relying on unsignedness of unsigned integers can be dangerous.

Like I said earlier, if you know the values are postive, it's safe.

In the example above, you initialize unsigned numbers with negative values,
and that yields predictably wrong values (since they can't be negative).


> To express reliable semantics, you'll have to employ a range-checked
> number class.

Not if you know the values are positive.

To take the example I gave earlier, to show how unsigned variables actually
may make it _more_ safe, by ensuring positiveness:

void f(int i)
{
if(i<10)
...
}

Note: As mentioned, if this used "unsigned", compilers will usually warn you
against a conversion from signed to unsigned, if it was called with a signed
value.

In the example above, it may be implied that "i" can't be negative, so
therefore it doesn't check for "i>=0", in the if(). However, this is only
_implied_, it's not expressed in the code.

Thus, if someone called f(), above, with a negative number, the if() would
yield true, despite that it was meant for just numbers between 0 and 9.

However, if "unsigned int i" was used instead, and they did that, even if
they used a signed number to call it, the resulting unsigned number would be
greater than the largest possible positive number, so the if() would be
false.

In other words, if "i" is assumed to be positive, you can ensure it with
unsigned. Or you can use an extra check for "i>=0". However, if you use
unsigned, you save a check, so it's more effcient.


> > Thus, you both communicate that the number is not negative (adding
> > semantics), and this is also enforced by the program, so you can avoid
an
> > extra check. :) Which means more efficiency.
>
> For small integers it is okay, but for large ones I'm afraid there is
> a possibility that 'big' negative numbers might wrap around to be
> interpreted positive and small enough.

What you are talking about here, is that if you interpred unsigned numbers
as signed numbers, or convert or cast them to signed numbers, or vice versa,
you may get wrong results.

Sure. I've never said anything else. That's how it works.

But I'm not talking about treating unsigned numbers as signed numbers!

I'm talking about treating e.g. an unsigned 8-bit number, which is 255, as
255. Not as -1.

Again, if you know the values are positive, it's safe.

There's no problem with them changing sign, if they get large enough, if you
only treat them as unsigned, which they are. Thus, you can use the full
range, not just small numbers, like you said.

This is just common sense.


> For example, (unsigned)-30000
> is evaluated less than (unsigned)40000 in a 16-bit environment.
> In such a case, what would be the answer? A larger unsigned integer?

In such case the answer is simple: You're using signed numbers, so signed
variables should be used to represent them.

This is not a problem with unsigned variables. :)

You're just using unsigned variables for something they are not meant for,
signed numbers. Therefore, you get wrong results.


> And there is also a possibility that unsigned integers that have
> 'semantically' negative values might be evaluated greater than
> most positive values.
>
> bool big_enough(unsigned x) { return x >= 100; }
> unsigned x = 10;
> // x is decremented below zero somehow...
> if (big_enough(x)) { /* ... */ }

Here, you get underflow.

This is no different from a signed number underflowing, except that for an
unsigned number, that occurs at zero, obviously enough, as that's the
smallest possible unsigned number you can have.


> Because of these kinds of surprises that unsigned integers give,
> I tend to prefer signed integers for quantitative values (which
> can be operands of arithmetic operations).

As long as the operations don't yield negative values (meaning unsigned
underflow), unsigned variables could be used. For example if it's actually
representing something that can't be negative.


> > This is actually so common in my program, using unsigned variables, if
the
> > values are unsigned, that I have the following typedef's in a common
> > header-file, to cut down the typing, when using unsigned variables:
> >
> > typedef unsigned int uint;
> > typedef unsigned short ushort;
> > typedef unsigned char uchar;
>
> Yes, they are so common indeed. What do you think of providing those
> in a standard header file, for convenience for and consistency among
> programmers?

Well, I certainly think it's pretty long to write e.g. "unsigned int",
rather than "uint", or something like that (and "unsigned" (implied
"unsigned int") is non-standard).

But, since there's no standard way of doing it, I just have it in a header
file.


Regards,

Terje Slettebo

tslettebo at chello dot no.

Mark Wilden

ulæst,
26. nov. 2001, 20.11.3026.11.2001
til
"Sungbom Kim" <musi...@bawi.org> wrote in message
news:3BFEEAE8...@bawi.org...
>
> I know that unsigned integers are...
> * very good for dealing with bit patterns or bit arrays
> * NOT recommended for just gaining one more bit of storage
> * NOT recommended for ensuring positiveness

I use unsigned integers when it makes no sense for a value to be negative
(this includes most for-loops). This is similar to using integral types
instead of floating types when I'm dealing with whole numbers--the practice
simply represents my intent more accurately.

Terje Slettebø

ulæst,
26. nov. 2001, 20.14.2226.11.2001
til
"James Kanze" <ka...@gabi-soft.de> wrote in message
news:d6651fb6.01112...@posting.google.com...
> Terje Sletteb <clcppm...@this.is.invalid> wrote in message

> news:<SX_L7.4334$Sa4.5...@news01.chello.no>...
> > "Sungbom Kim" <musi...@bawi.org> wrote in message
> > news:3BFEEAE8...@bawi.org...
> > > Can you suggest recommended/discouraged usage of unsigned integers?
>
> > > I know that unsigned integers are...
> > > * very good for dealing with bit patterns or bit arrays
> > > * NOT recommended for just gaining one more bit of storage
> > > * NOT recommended for ensuring positiveness
>
> > Well, you can of course use them to get one more bit of storage.
>
> But should you? If the design logic suggests signed integers, for
> whatever reason, using unsigned just to gain one bit is probably short
> sighted.

Yes, I agree with that.

My reply was based on using unsigned variables for unsigned values, not for
signed values.

I gave a longer reply to these things, in another message to Sungbom Kim's
message, so I won't repeat it here.


> Because it doesn't work. An unsigned number is always positive. Even
> when it was initialized with a negative number. This can potentially
> hide errors.

Look at the example I gave. It does work.

This does, however, imply that it's initialized with unsigned values, not
signed values.


> > I find unsigned numbers very useful, actually. I tend to use it to
> > put semantics into my program (similar to using const), that is
> > enforced by the program. It's simple: When you use an unsigned
> > number, you _know_ it can't be negative (thus, you _can_ ensure
> > positiveness).
>
> The problem is, you can know that the value you got isn't negative,
> but you can't know that the caller didn't try to pass you a negative.

Like I mentioned in the other reply, compilers usually give a warning for
such conversions.

I keep my compiler at the highest warning-level, and then selectively
disable warnings, so I get such warnings.


> > Since it can't be negative, you may also avoid checks for
> > negativeness, like this:
>
> > void f(int i) // Signed
> > {
> > if(i>=0 && i<10)
> > ...
> > }
>
> > void f(unsigned int i) // Unsigned
> > {
> > if(i<10)
> > ...
> > }
>
> > Thus, you both communicate that the number is not negative (adding
> > semantics), and this is also enforced by the program, so you can
> > avoid an extra check. :) Which means more efficiency.
>
> You have to communicate the range out of band anyway; why is it so
> important to avoid the >= 0 comment, but not the < 10 comment? And I
> would expect any decent compiler to generate the same code for your
> two examples, so I don't see where the efficiency argument comes into
> play.

Yes, you have to include the check for the other end (10).

A compiler _might_ be able to produce the same code. If it realizes that
(signed) (i>=0 && i<10) is the same as (unsigned) (i<10).

I didn't actually think of this.

It may be unresonable to expect of a compiler, thought. This is a special
case. For example, if you used "if(i>0 && i<10)", it couldn't do this
transformation (and you couldn't use unsigned for range-checking).


I did a test for this, now. The following program:

--- Start ---

int a,b; // Globals, to ensure they aren't optimized away

void f(int i)


{
if(i>=0 && i<10)

a=10;
}

int main()
{
f(b);
}

--- End --


The compiler settings is for full optimization (global optimization,
optimize for speed, etc.)


The following is the output of the Intel C++ 5.0 compiler:

12: if(i>=0 && i<10)
00401143 mov eax,dword ptr [i]
00401146 test eax,eax // i<0?
00401148 jl f+1Ch (0040115c) // jump
0040114A mov eax,dword ptr [i]
0040114D cmp eax,0Ah // i>=10?
00401150 jge f+1Ch (0040115c) // jump
13: a=10;
00401152 mov dword ptr [a (00428be4)],0Ah

Yes, this is actual code. It's nothing to fear. :)

I like concrete examples, where you can actually test things.


The following is the output for Visual C++ 6.0:

12: if(i>=0 && i<10)
00401168 cmp dword ptr [ebp+8],0 // i<0?
0040116C jl f+2Eh (0040117e) // jump
0040116E cmp dword ptr [ebp+8],0Ah // i>=10?
00401172 jge f+2Eh (0040117e) // jump
13: a=10;
00401174 mov dword ptr [a (00438490)],0Ah


The following is the unsigned version (only Intel C++ is shown, the other
one is the same way):

12: if(i<10)
00401143 mov eax,dword ptr [i]
00401146 cmp eax,0Ah // i<10?
00401149 jae f+15h (00401155) // jump (if above or equal)
(unsigned values)
13: a=10;
0040114B mov dword ptr [a (00428be4)],0Ah


As you can see, you save a jump.

In today's deeply pipelined processors, a conditional jump can actually be
quite costly, as you risk a branch-misprediction, so it can be several times
slower, than if no branch was taken.

You asked where the efficiency argument comes into play. Here it is.


As is shown, neither of the compilers I tried this with, was able to produce
the unsigned version. I don't think one can expect it, either, since it's a
special case.


> > This is actually so common in my program, using unsigned variables,
> > if the values are unsigned, that I have the following typedef's in a
> > common header-file, to cut down the typing, when using unsigned
> > variables:
>
> > typedef unsigned int uint;
> > typedef unsigned short ushort;
> > typedef unsigned char uchar;
>
> That's dangerous, but for a completely different reason. These names
> seem so popular that a lot of libraries (Posix, for example) try and
> define them. I avoid them like the plague, because of the risk of
> name conflicts.

Well, I haven't had any problems with them. I use Windows, and Windows tend
to use a lot of typedefs, but they tend to use uppercase names, so they
don't clash.

Besides, it's not dangerous. If you try to redefine an existing symbol,
using typedef, you'll get an error at compile-time. Simple and clear. So
there's no danger of inadvertent name-conflics.


> (But this may be a hang-over from my C days. In C++,
> I think that multiple typedef's of the same name are legal, as long as
> they define the same types. And I've yet to see a library which
> defined them differently than you do here.)

Yes, at least with my compiler, the following is possible, now:

typedef int test;
typedef int test;

The following gave an "invalid redeclaration" error. As you can see, it's
safe, as it'll tell you if you try to change the meaning of the typedefs (or
if they are defined for something else):

typedef int test;
typedef double test; // Error, invalid redeclaration

It gives an error. It doesn't subtly change the meaning, without an error or
warning. That could be have been dangerous.

As it's now, it's safe.

There really has to be this checking for different redeclaration, otherwise
it would have been unsafe to use typedef, in general.


Regards,

Terje Slettebo

tslettebo at chello dot no.

Terje Slettebø

ulæst,
26. nov. 2001, 20.15.5126.11.2001
til
"David Bradley" <dbradl...@netscape.com> wrote in message
news:3C027A80...@netscape.com...

> James Kanze wrote:
>
> > The problem is, you can know that the value you got isn't negative,
> > but you can't know that the caller didn't try to pass you a negative.
>
> You can't know but the caller should get a warning from the compiler
> complaining about the passing of a signed to an unsigned. Isn't that
> worth something? If I'm implementing a function and a negative number
> makes no sense, doesn't it make more sense to let the compiler tell my
> caller that he's doing something potentially bad, rather than waiting
> for a runtime assert/error.

My point exactly.

This can actually make it _more_ safe, than having an a signed variable, but
where it doesn't make any sense for it to be negative, in the function, so
you would otherwise have to check for negativeness, since it's signed.


Regards,

Terje Slettebo

tslettebo at chello dot no.

Pete Becker

ulæst,
27. nov. 2001, 04.24.4427.11.2001
til
Michiel Salters wrote:
>
> In article <3C005609...@acm.org>, Pete Becker says...
> >
> >Francis Glassborow wrote:
> >>
> >> In article <3BFEEAE8...@bawi.org>, Sungbom Kim <musi...@bawi.org>
> >> writes
> >> >How about using unsigned integers for quantities that just don't
> >> >go below zero, for example months(1..12), days of month(1..31),
> >> >days of week(0..6 or 1..7), etc. in calendar programs?
> >>
> >> I would far prefer to see such entities represented by UDTs. A class
> >> does not just provide a mechanism for hiding data, it allows the
> >> designer to determine what is appropriate behaviour. A month is not any
> >> kind of int (you cannot multiply or divide months representing elements
> >> of a calendar, you can add/subtract an integer value to a month but even
> >> that requires special processing to handle going outside the range)
> >>
> >
> >You also use the month number as an index into an array of ints to get
> >number of days in a month,
> [SNIP]
> Using INT_MAX-1 as an array index is about as bad as using -1. So I don't
> believe in array indexing as a reason to use unsigned ints.

I didn't say anything about unsigned ints. I objected UDTs and the
arguments presented in their favor.

--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Pete Becker

ulæst,
27. nov. 2001, 04.25.3427.11.2001
til
James Kanze wrote:
>
> The problem is that the checking is worthless. Not only can a month
> not be negative, it can't even be 0, nor > 12.

Well, > 13 for lunar calendars. <g> But that illustrates why trying to
pin these things down can be risky.

--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Sungbom Kim

ulæst,
27. nov. 2001, 04.25.5927.11.2001
til
David Bradley wrote:
>
> James Kanze wrote:
>
> > The problem is, you can know that the value you got isn't negative,
> > but you can't know that the caller didn't try to pass you a negative.
>
> You can't know but the caller should get a warning from the compiler
> complaining about the passing of a signed to an unsigned. Isn't that
> worth something? If I'm implementing a function and a negative number
> makes no sense, doesn't it make more sense to let the compiler tell my
> caller that he's doing something potentially bad, rather than waiting
> for a runtime assert/error.

I don't get any warning under gcc 2.95.4 (even with -Wall):

void foo(unsigned);

int main(void)
{
int x = -1;
foo(x);
}

Anyway, if it had given a warning about passing a signed to an
unsigned, I would have gotten so much warnings of the same kind
since signed integers are so common (including integer literals),
which would have quickly made me neglectful.

--
Sungbom Kim <musi...@bawi.org>

Pete Becker

ulæst,
27. nov. 2001, 04.28.1927.11.2001
til
David Bradley wrote:
>
> James Kanze wrote:
>
> > The problem is, you can know that the value you got isn't negative,
> > but you can't know that the caller didn't try to pass you a negative.
>
> You can't know but the caller should get a warning from the compiler
> complaining about the passing of a signed to an unsigned.
>

The conversion from signed to unsigned is well-defined and useful. How
can the compiler know whether passing a signed value is a mistake or
deliberate?

--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Terje Slettebø

ulæst,
27. nov. 2001, 12.37.5827.11.2001
til
"Sungbom Kim" <musi...@bawi.org> wrote in message
news:3C02E5A2...@bawi.org...

> David Bradley wrote:
> >
> > James Kanze wrote:
> >
> > > The problem is, you can know that the value you got isn't negative,
> > > but you can't know that the caller didn't try to pass you a negative.
> >
> > You can't know but the caller should get a warning from the compiler
> > complaining about the passing of a signed to an unsigned. Isn't that
> > worth something? If I'm implementing a function and a negative number
> > makes no sense, doesn't it make more sense to let the compiler tell my
> > caller that he's doing something potentially bad, rather than waiting
> > for a runtime assert/error.
>
> I don't get any warning under gcc 2.95.4 (even with -Wall):

It does give a warning in Intel C++ and VC++.


> void foo(unsigned);
>
> int main(void)
> {
> int x = -1;
> foo(x);
> }
>
> Anyway, if it had given a warning about passing a signed to an
> unsigned, I would have gotten so much warnings of the same kind
> since signed integers are so common (including integer literals),
> which would have quickly made me neglectful.

If you're going to call it, with signed types, then it may be better to have
the parameter signed, as I mentioned in my message. Because then, the
compiler no longer ensures you get the correct value.


Regards,

Terje Slettebo

tslettebo at chello dot no.

Terje Slettebø

ulæst,
27. nov. 2001, 12.40.2127.11.2001
til
"Pete Becker" <peteb...@acm.org> wrote in message
news:3C02F59E...@acm.org...

> David Bradley wrote:
> >
> > James Kanze wrote:
> >
> > > The problem is, you can know that the value you got isn't negative,
> > > but you can't know that the caller didn't try to pass you a negative.
> >
> > You can't know but the caller should get a warning from the compiler
> > complaining about the passing of a signed to an unsigned.
> >
>
> The conversion from signed to unsigned is well-defined and useful. How
> can the compiler know whether passing a signed value is a mistake or
> deliberate?

At least in some compilers, you can get a warning, for this. Then, if you
want, you can disable the warning. That makes it up to the user to determine
whether or not this should be considered correct, or an error, in the
program,


Regards,

Terje Slettebo

tslettebo at chello dot no.

Mike

ulæst,
27. nov. 2001, 13.02.1827.11.2001
til
I've been reading the arguments back and forth, and I haven't seen one
question addressed: What does the standard say about overflows and
underflows of integral types? Everybody 'knows' that (unsigned
char)-1 is 255, but is this a guarantee?

Pete Becker

ulæst,
27. nov. 2001, 18.06.0727.11.2001
til
Terje Slettebø wrote:
>
> Yes, when you _convert_ from signed values.
>
> What happens is that the bits are interpreted as unsigned, rather than
> signed values, which gives a different result.
>
> No operation is actually performed on the value. No modulo, or otherwise.
> It's just the interpretation of the same bits, that changes, and therefore
> you get a different value.
>

C and C++ both require that the conversion be done modulo UINT_MAX + 1
(or whatever the appropriate max value is for the particular type). On
many architectures that can be done by treating the bits as an unsigned
value, without making any changes. But on architectures where this isn't
true the bit pattern has to be adjusted as if the modulus operation had
been done.

--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

ulæst,
27. nov. 2001, 18.10.3427.11.2001
til
David Bradley <dbradl...@netscape.com> wrote in message
news:<3C027A80...@netscape.com>...
> James Kanze wrote:

> > The problem is, you can know that the value you got isn't
> > negative, but you can't know that the caller didn't try to pass
> > you a negative.

> You can't know but the caller should get a warning from the compiler
> complaining about the passing of a signed to an unsigned. Isn't that
> worth something? If I'm implementing a function and a negative
> number makes no sense, doesn't it make more sense to let the
> compiler tell my caller that he's doing something potentially bad,
> rather than waiting for a runtime assert/error.

Do you mean that you want the compiler to give a warning anytime you
pass an integral literal to the function? Or that your uses should
get into the habit of writing 0U, rather than just 0?

I like the idea of compile time checking, but for better or worse,
C/C++ prefers int's to all other integral types.

--
James Kanze mailto:ka...@gabi-soft.de
Beratung in objektorientierer Datenverarbeitung --
-- Conseils en informatique orientée objet
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany, Tél.: +49 (0)69 19 86 27

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

ulæst,
27. nov. 2001, 18.12.0927.11.2001
til
Terje Slettebø <clcppm...@this.is.invalid> wrote in message
news:<jBvM7.4518$Sa4.6...@news01.chello.no>...

> "Sungbom Kim" <musi...@bawi.org> wrote in message
> news:3C01A154...@bawi.org...

> > Terje Sletteb wrote:

> > > "Sungbom Kim" <musi...@bawi.org> wrote in message
> > > news:3BFEEAE8...@bawi.org...
> > > > Can you suggest recommended/discouraged usage of unsigned integers?

> > > > I know that unsigned integers are...
> > > > * very good for dealing with bit patterns or bit arrays
> > > > * NOT recommended for just gaining one more bit of storage
> > > > * NOT recommended for ensuring positiveness

> > > Well, you can of course use them to get one more bit of
> > > storage. There's nothing wrong with that. It should be ok to
> > > use it to ensure positiveness, too, why not?

> > Bjarne Stroustrup says in The C++ Programming Language, 4.4:

> > The <unsigned> integer types are ideal for uses that treat
> > storage as a bit array. Using an <unsigned> instead of an
> > <int> to gain one more bit to represent positive integers is
> > almost never a good idea. Attempts to ensure that some values
> > are positive by declaring variables <unsigned> will typically
> > be defeated by the implicit conversion rules.

> > Why would he have said so?

> I think it's important that when advice is given, not only the
> advice, but also _why_ this is adviced, should be included. Scott
> Meyer's "Effective C++" books are excellent at this.

Scott is, of course, the one who convinced me to eshew unsigned.

> They explain the reason for the advice, so you can assess, yourself,
> whether or not it applies to the situation at hand.

> I have also experience with assembly programming, so I know how
> signed and unsigned are treated at that level.

> There is nothing wrong with using an unsigned number, to gain one
> more bit of storage. If others in the newsgroup disagrees, feel free
> to give reasons for the opposite.

> To take the example of char. Signed char gives the range -128 to
> 127. Unsigned char gives 0 to 255. Not useful? I'd definitely think
> it's useful. You just got twice as large positive range. The same
> goes for all the integers.

The problem is: if 128 is not sufficient today, then 256 will not be
sufficient tomorrow. If 128 isn't sufficient, then use short.

> If you used a signed char to represent an 8-bit char, it wouldn't
> fit.

This is a *very* real problem. However, the type for characters in
C++ is char, not unsigned char, and there isn't much you can do about
it. (String literals have type char const[], for example.) It's a
real pain when some of your daily character values have negative
values, and you have to continually cast to unsigned char to see them,
but there isn't much you can do about it.

If we were starting from scratch, I'm sure that char would be required
to be unsigned, or at least that it would be required to have
sufficient range to represent all of the characters in the native
character set (as opposed to the basic character set) as positive
values. But the problem here is the language. Representing
characters *is* one place where unsigned makes sense. Not because of
one more bit, necessarily, but because the character codes are defined
as positive values, are used as indexes into arrays, etc., etc. But
for representing characters, you don't have any choice: string
literals are char's, not unsigned char's; all of the functions in
<string.h> take char*, not unsigned char*, and of course, you have
std::string based on char, and not unsigned char.

Of course, the current trend is to use Unicode anyway, so who cares
about char. All that counts is wchar_t. But the language says even
less about this; to be useful, it should be a 32 bit typed, signed or
unsigned doesn't matter (since Unicode only needs around 20 bits).
But the standard doesn't require this -- as far as the standard is
concerned, wchar_t can be exactly the same as char.

> You would only get half the range.

> What about you, don't you think this is useful?

In the special case of representing characters on an 8 bit machine,
yes. Elsewhere, no.

> I think Bjarne Stroustrup gave the blanket advice, to warn against
> if people used unsigned types to represent _signed_ values, and uses
> unsigned, just to get one more bit of storage. If the numbers then
> happen to be negative, you get the wrong values (since unsigned
> types can't represent negative values).

No. He said that the extra bit didn't matter. With few exceptions,
it doesn't.

> This is why I think he said that. If you use unsigned types to
> represent values that can actually be negative, you get the wrong
> values.

Obviously. But I don't think anyone is that dumb.

> If you represent unsigned values with unsigned integers, it's
> perfectly safe. It's not just safe, it can be an advantage, because
> you specify a more specific type (the way an UDT is a more specific
> type), and the program enforces it.

If you reread what Bjarne wrote, what he says is that because of
implicit type conversions, the program *doesn't* enforce it. It just
gives the impression that it does. So you have a choice: signed, and
a runtime check, or unsigned, and no check what so ever.

> The problem is if people take advice, without understanding why it's
> adviced, it may be taken as advice even in areas it doesn't apply,
> and may in fact be a disadvantage.

> Regarding ensuring positiveness. I gave an example that demonstrates
> that the positiveness is ensured ("if(i<10) ... // i>=0 && i<10
> "). Thus, this is a counter-example that it's possible.

> Again, I think he gave the advice, if people try to ensure
> positiveness, in the sense of a conversion. For that, it's no good,
> and I agree. Again, the problem is that, at least in the short
> quote, here, little specific explanation on _why_ it's adviced, is
> given.

> As an example:

> int i=-1;
> unsigned int j=i; // No good as conversion; j will be 255, not 1.

More likely j will be a lot larger than 255. According to the
standard, the results are implementation defined, and may trap. In
practice, you will generally get INT_MIN.

> However, again, if you know the values are positive, it's safe to
> use unsigned types, and, like in the example with if(), above, it
> actually makes it more efficient.

Have you actually measured the difference in a real program, with a
modern compiler? And found it to be a bottleneck in your code?

Compilers generally know what the machine instructions do. The
compile I worked on (almost 15 years ago) had no trouble optimizing
the comparison with signed, and generated exactly the same code in
both cases.

> Besides, as mentioned, it documents that the value is always
> positive.

It does document the intent that the values be positive. It doesn't
document the intent that they be less than 10, however, so I'm not
really convinced that you've gained anything.

> > > I find unsigned numbers very useful, actually. I tend to use it
> > > to put semantics into my program (similar to using const), that
> > > is enforced by the program. It's simple: When you use an
> > > unsigned number, you _know_ it can't be negative (thus, you
> > > _can_ ensure positiveness).

> > You also have to mind that variables of unsigned integral types
> > are just *interpreted* as non-negative values (via modulo
> > operation);

Actually, there's a real reason to use unsigned hidden in this
statement. Overflow is a defined operation in unsigned arithmetic;
it's undefined behavior in signed arithmetic. So in the few cases
where defined overflow is desired (calculating hash values, for
example), unsigned must be used. A somewhat weaker constraint
involves integral division and modulo (the / and % operators), whose
results are implementation defined for negative values.

> Yes, when you _convert_ from signed values.

> What happens is that the bits are interpreted as unsigned, rather
> than signed values, which gives a different result.

That is *not* what happens, although on many hardware, the results are
the same as what does happen, and the compiler optimizes to exploit
this fact. The results of converting a negative value to an unsigned
are defined by the standard as (UINT_MAX + 1) + negative_value.

> No operation is actually performed on the value.

On most machines.

> No modulo, or otherwise. It's just the interpretation of the same
> bits, that changes, and therefore you get a different value.

> In use, unsigned variables behave just like signed variables, except
> they can't be negative, so operations that would normally result in
> negative values, like your example below, here, you get the wrong
> values.

> Thus, regarding interpreting the numbers, that is the same way, for
> both signed and unsigned numbers. Unsigned numbers aren't
> interpreted in any special way. For an 8-bit number, for example,
> 255 and -1 are two interpretations of the case when all bits are
> set.

Depending on the hardware, when all of the bits are set, you might get
-1, -2 or INT_MIN. I've seen examples of all of them.

> As you can see, they are both interpretations of the same bit
> pattern. Unsigned or signed numbers aren't treated in any special
> way.

As I can see, you are basing your assumptions on the behavior of one
particular machine, rather than what the standard guarantees.

> In addition, the operations on numbers work the same way, whether
> they are interpreted as signed or unsigned.

> > nothing prevents you from assigning them negative numbers or
> > making them pass below zero:

> That's correct.

> You would, however, usually get a warning from the compiler, if you
> try to assign a signed value to an unsigned variable.

In which case, you would get so many warnings as to make the compiler
unusable (at least with these warnings turned on).

> Regarding passing below zero, that's an underflow, for unsigned
> variables, and overflows and underflows give no error, regardless if
> you're using signed or unsigned variables. Unsigned variables are no
> different in this respect.

Underflow and overflow in the case of signed arithmetic is undefined
behavior. Your program might crash. I believe that there was once a
compiler where it actually would (CenterLine). Underflow and overflow
in the case of unsigned arithmetic has defined semantics.

> If you mean, by ensuring positiveness, that you can't do:

> unsigned int a=-1; // a won't be 1, but UINT_MAX (as you show in your
> example)

> then I agree with you.

Then we agree.

Whatever the architecture, a will *not* be equal to -1, which is what
the user wanted. But there is no compile time error. And it is
impossible to verify at runtime that the value isn't what was wanted,
because it got changed. This is precisely the argument against
unsigned values.

> But this was not what I meant, when I said you can ensure
> positiveness.

> I was not talking about conversions. I was talking about that if you
> have an unsigned type, it is _ensured_ that the number is
> positive. The simple reason is that it can't be negative.

But the reason it is ensured positive isn't that the user can't
accidentally pass a negative value; it is that if the user does so, it
gets implicitly (and silently) converted to some incorrect positive
value.

> Whether a conversion from a signed, to an unsigned type, yield
> correct values, is an entirely different matter.

Unless, of course, you want the program to give the correct results.

[...]
[example requiring number between 0 and 10]


> However, if "unsigned int i" was used instead, and they did that,
> even if they used a signed number to call it, the resulting unsigned
> number would be greater than the largest possible positive number,
> so the if() would be false.

Except on a Unisys series A, for example.

The entire gist of your argument boils down that if you know the
number is positive, using unsigned values is safe. I don't think that
anyone could argue about that, but your conclusion rests on the
somewhat shakey assumption that no client code could ever make the
mistake of accidentally passing a negative value.

--
James Kanze mailto:ka...@gabi-soft.de
Beratung in objektorientierer Datenverarbeitung --
-- Conseils en informatique orientée objet
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany, Tél.: +49 (0)69 19 86 27

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Pete Becker

ulæst,
27. nov. 2001, 18.12.3327.11.2001
til
Terje Slettebų wrote:
>
> "Pete Becker" <peteb...@acm.org> wrote in message
> news:3C02F59E...@acm.org...
> > David Bradley wrote:
> > >
> > > James Kanze wrote:
> > >
> > > > The problem is, you can know that the value you got isn't negative,
> > > > but you can't know that the caller didn't try to pass you a negative.
> > >
> > > You can't know but the caller should get a warning from the compiler
> > > complaining about the passing of a signed to an unsigned.
> > >
> >
> > The conversion from signed to unsigned is well-defined and useful. How
> > can the compiler know whether passing a signed value is a mistake or
> > deliberate?
>
> At least in some compilers, you can get a warning, for this.

Yes, some compilers are presumptious. <g>

--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Pete Becker

ulæst,
27. nov. 2001, 18.12.5627.11.2001
til
Mike wrote:
>
> I've been reading the arguments back and forth, and I haven't seen one
> question addressed: What does the standard say about overflows and
> underflows of integral types? Everybody 'knows' that (unsigned
> char)-1 is 255, but is this a guarantee?
>

4.7/2:

If the destination type is unsigned, the resulting value
is the least unsigned integer congruent to the source
integer (modulo 2^n where n is the number of bits used
to represent the unsigned type). [Note: In a two’s complement
representation, this conversion is conceptual and there is
no change in the bit pattern (if there is no truncation). ]

--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

ulæst,
27. nov. 2001, 18.13.2027.11.2001
til
Terje Slettebø <clcppm...@this.is.invalid> wrote in message
news:<GfxM7.4529$Sa4.6...@news01.chello.no>...

> "James Kanze" <ka...@gabi-soft.de> wrote in message
> news:d6651fb6.01112...@posting.google.com...
> > Terje Sletteb <clcppm...@this.is.invalid> wrote in message
> > news:<SX_L7.4334$Sa4.5...@news01.chello.no>...
> > > "Sungbom Kim" <musi...@bawi.org> wrote in message
> > > news:3BFEEAE8...@bawi.org...
> > > > Can you suggest recommended/discouraged usage of unsigned integers?
>
> > > > I know that unsigned integers are...
> > > > * very good for dealing with bit patterns or bit arrays
> > > > * NOT recommended for just gaining one more bit of storage
> > > > * NOT recommended for ensuring positiveness

> > > Well, you can of course use them to get one more bit of storage.

> > But should you? If the design logic suggests signed integers,
> > for whatever reason, using unsigned just to gain one bit is
> > probably short sighted.

> Yes, I agree with that.

So what are we arguing about? I was responding to the statement "you


can of course use them to get one more bit of storage."

> My reply was based on using unsigned variables for unsigned values,
> not for signed values.

But nobody has suggested using them for values that might be negative.

> I gave a longer reply to these things, in another message to Sungbom
> Kim's message, so I won't repeat it here.

> > Because it doesn't work. An unsigned number is always positive.
> > Even when it was initialized with a negative number. This can
> > potentially hide errors.

> Look at the example I gave. It does work.

I did look, and it doesn't work.

More generally, the use of unsigned tends to hide errors. Consider
functions like std::vector::resize. Most of the time, the parameter
will be the result of an expression. If some of the input to the
expression has an unexpected value, and I've forgotten to check it,
the results may end up negative. The *real* results. If I'm
calculating with signed values, I can, of course, check this before
hand. But whatever I do, nothing prevents me from passing this
negative result to std::vector::resize, because the negative value
will silently be converted to some positive value. Typically, the
resulting positive value will be large enough to cause a bad_alloc
exception on smaller machines. But if I compile in 64 bit mode on the
machine I'm on now, all that will happen is that I'll use an awful lot
of memory, the machine will thrash a little (because I've only got 4
Gig of real memory, and my one little process is taking it all), and
the program will continue running.

This is a real problem, and there is really no excuse for using
unsigned types in such interfaces.

The only times unsigned types are justified in application code is
when you *want* the defined overflow they provide. And such cases are
very rare; the *only* one I can think of off hand is calculating a
hash code. The are also useful in some system code where you really
do have to consider *all* of the memory as a single array of so many
bytes (the implementation of sbrk comes to mind).

> This does, however, imply that it's initialized with unsigned
> values, not signed values.

> > > I find unsigned numbers very useful, actually. I tend to use it
> > > to put semantics into my program (similar to using const), that
> > > is enforced by the program. It's simple: When you use an
> > > unsigned number, you _know_ it can't be negative (thus, you
> > > _can_ ensure positiveness).

> > The problem is, you can know that the value you got isn't
> > negative, but you can't know that the caller didn't try to pass
> > you a negative.

> Like I mentioned in the other reply, compilers usually give a
> warning for such conversions.

Such warnings would pretty much render the compiler useless unless you
turned them off. Do you really want a warning for:

std::vector< int > v ;
v.resize( 0 ) ;

[...]


> A compiler _might_ be able to produce the same code. If it realizes
> that (signed) (i>=0 && i<10) is the same as (unsigned) (i<10).

It's not that difficult. I've worked on compilers which did it. It's
a common enough idiom that it's worth checking for.

> I didn't actually think of this.

> It may be unresonable to expect of a compiler, thought. This is a
> special case.

It's a very common special case, however. Which makes it worth doing.

> For example, if you used "if(i>0 && i<10)", it couldn't do this
> transformation (and you couldn't use unsigned for range-checking).

Depending on the compiler, it might be better to generate the
equivalent of:

if ( unsigned( i ) - 1 < 9 )

Finding these sort of optimizations is pretty standard compiler fare
nowadays.

> --- Start ---

> int main()
> {
> f(b);
> }

> --- End --

There's regression, then, because the Intel PL/M compilers of the late
1970's did it better.

> In today's deeply pipelined processors, a conditional jump can
> actually be quite costly, as you risk a branch-misprediction, so it
> can be several times slower, than if no branch was taken.

Correct. This is why any good compiler will try and eliminate the
jump if possible. Depending on what you do in the if, it is often
possible to eliminate all of them. As I said, the Intel compilers
have been good at this in the past. I'm both surprised and
disappointed that they don't do better.

> You asked where the efficiency argument comes into play. Here it is.

> As is shown, neither of the compilers I tried this with, was able to
> produce the unsigned version. I don't think one can expect it,
> either, since it's a special case.

The compiler I worked on in the late 80's did it. I know that the old
Intel PL/M compilers did some special optimizations to avoid jumps in
the late 70's, but I don't know if this was one of them. (I think
that part of their optimizations were due to the fact that PL/M didn't
short-circuit the evaluation. Apparently, the authors of the C
compiler missed the fact that in some cases, the second part of the
expression has no side effects, and it is cheaper to evaluate the
entire expression than to have the two jumps.)

Which, of course, leaves open the question of whether this has ever
been a bottleneck in real code. (Most of the time, when your running
that close to the limits, all bounds checking goes out the door.)

--
James Kanze mailto:ka...@gabi-soft.de
Beratung in objektorientierer Datenverarbeitung --
-- Conseils en informatique orientée objet
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany, Tél.: +49 (0)69 19 86 27

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

ulæst,
27. nov. 2001, 18.14.0827.11.2001
til
"Mark Wilden" <ma...@mwilden.com> wrote in message
news:<u05712o...@news.supernews.com>...

> "Sungbom Kim" <musi...@bawi.org> wrote in message
> news:3BFEEAE8...@bawi.org...

> > I know that unsigned integers are...
> > * very good for dealing with bit patterns or bit arrays
> > * NOT recommended for just gaining one more bit of storage
> > * NOT recommended for ensuring positiveness

> I use unsigned integers when it makes no sense for a value to be
> negative (this includes most for-loops). This is similar to using
> integral types instead of floating types when I'm dealing with whole
> numbers--the practice simply represents my intent more accurately.

I agree in theory, and did this for a long time myself. In the end,
however, the implicit conversions mean that you've just added another
possible error that you can't effectively check for. In C/C++, an
integral type is int, unless there are imperative reasons to use
something else (lack of range, need for modulo overflow handling,
etc.).

--
James Kanze mailto:ka...@gabi-soft.de
Beratung in objektorientierer Datenverarbeitung --
-- Conseils en informatique orientée objet
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany, Tél.: +49 (0)69 19 86 27

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Francis Glassborow

ulæst,
27. nov. 2001, 18.15.3727.11.2001
til
In article <a509b414.01112...@posting.google.com>, Mike
<friedl...@yahoo.com> writes

>I've been reading the arguments back and forth, and I haven't seen one
>question addressed: What does the standard say about overflows and
>underflows of integral types? Everybody 'knows' that (unsigned
>char)-1 is 255, but is this a guarantee?

Effectively except that that should be (2^n -1) where n is the number of
bits in the representation of the unsigned char (or in general the
unsigned integer type)


--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Ron Natalie

ulæst,
27. nov. 2001, 18.17.1127.11.2001
til

Mike wrote:
>
> I've been reading the arguments back and forth, and I haven't seen one
> question addressed: What does the standard say about overflows and
> underflows of integral types?

What happens on signed integers when you overflow is implementation
defined (what it overflows to and whether some sort of exception is
generated).

For unsigned integers, there is no overflow. All your math wraps
around modulo 2**number_of_bits.

> Everybody 'knows' that (unsigned
> char)-1 is 255, but is this a guarantee?

Certainly not. There's nothing that says that a char is exactly 8 bits.

However, I think your question doesn't really involve overflow, but the
conversion between signed and unsigned. This is well defined. The conversion
is that the negative integer value is converted to the smallest positive
value modulo 2**number_of_bits.

So, if you "know" that there are 8 bits in your unsigned char, then yes
(unsigned char) -1 is guanteed to be 255.

Mark Wilden

ulæst,
27. nov. 2001, 21.50.0527.11.2001
til
"James Kanze" <ka...@gabi-soft.de> wrote in message
news:d6651fb6.01112...@posting.google.com...
>
> > I use unsigned integers when it makes no sense for a value to be
> > negative (this includes most for-loops). This is similar to using
> > integral types instead of floating types when I'm dealing with whole
> > numbers--the practice simply represents my intent more accurately.
>
> I agree in theory, and did this for a long time myself. In the end,
> however, the implicit conversions mean that you've just added another
> possible error that you can't effectively check for.

I would just _love_ to have a good reason not to use unsigneds as a rule of
thumb for counts because of the extra typing and horizontal scrolling. :)

But I don't see what possible error a usage like this could lead to:

for (unsigned i = 0; i < x; ++i)
// ...

To me, using an int here is just wrong, because an int is signed, and
signedness is semantically meaningless for i. I'd say the same about
anything that counts.

I think I know what you're saying--that

unsigned x;
// ....
x -= y; // error if y > x

where x is < y would be a bug I couldn't test for later (though there's
nothing to prevent me from testing for y > x before the subtraction).. Is
that correct?

> In C/C++, an
> integral type is int, unless there are imperative reasons to use
> something else (lack of range, need for modulo overflow handling,
> etc.).

This sounds good in theory, but I'd be interested in practical reasons why I
should change to int in the first loop above, since I'd prefer to do so for
readability. "C/C++'s integral type is a (signed) int" is almost good
enough, but if I could add fewer bugs to the mix, I'd be sold. :)

Terje Slettebø

ulæst,
28. nov. 2001, 07.55.2528.11.2001
til
"Pete Becker" <peteb...@acm.org> wrote in message
news:3C03AEDE...@acm.org...

> Terje Sletteb wrote:
> >
> > Yes, when you _convert_ from signed values.
> >
> > What happens is that the bits are interpreted as unsigned, rather than
> > signed values, which gives a different result.
> >
> > No operation is actually performed on the value. No modulo, or
otherwise.
> > It's just the interpretation of the same bits, that changes, and
therefore
> > you get a different value.
> >
>
> C and C++ both require that the conversion be done modulo UINT_MAX + 1
> (or whatever the appropriate max value is for the particular type). On
> many architectures that can be done by treating the bits as an unsigned
> value, without making any changes. But on architectures where this isn't
> true the bit pattern has to be adjusted as if the modulus operation had
> been done.

I understand.

James Kanze said the same, in a posting.

I had just tested it with the compiler. I hadn't checked it in the standard.

Like I said in that message, I'll read up on this, and reconsider it, before
giving feedback.


Regards,

Terje Slettebo

tslettebo at chello dot no.

Terje Slettebø

ulæst,
28. nov. 2001, 08.00.4528.11.2001
til
"James Kanze" <ka...@gabi-soft.de> wrote in message
news:d6651fb6.01112...@posting.google.com...
> Terje Sletteb <clcppm...@this.is.invalid> wrote in message
> news:<GfxM7.4529$Sa4.6...@news01.chello.no>...
> > "James Kanze" <ka...@gabi-soft.de> wrote in message
> > news:d6651fb6.01112...@posting.google.com...
> > > Terje Sletteb <clcppm...@this.is.invalid> wrote in message
> > > news:<SX_L7.4334$Sa4.5...@news01.chello.no>...
> > > > "Sungbom Kim" <musi...@bawi.org> wrote in message
> > > > news:3BFEEAE8...@bawi.org...
> > > > > Can you suggest recommended/discouraged usage of unsigned
integers?
> >
> > > > > I know that unsigned integers are...
> > > > > * very good for dealing with bit patterns or bit arrays
> > > > > * NOT recommended for just gaining one more bit of storage
> > > > > * NOT recommended for ensuring positiveness
>
> > > > Well, you can of course use them to get one more bit of storage.
>
> > > But should you? If the design logic suggests signed integers,
> > > for whatever reason, using unsigned just to gain one bit is
> > > probably short sighted.
>
> > Yes, I agree with that.
>
> So what are we arguing about? I was responding to the statement "you
> can of course use them to get one more bit of storage."

I agree if you use _signed_ values. You said if it would be best to use
signed vaules, then I agree, it would be no point in using unsigned for
that, as it can't represent it.

I said it was safe to use the full range of unsigned variables, if you're
just using unsigned values.

By the way, I've replied more in the other posting to you, and like I said
there, I'll have to read up on this, and reconsider this.


> I did look, and it doesn't work.

Ok, yes, there can be an implicit conversion from int to unsigned int.

I meant that it worked, in the sense that such conversions tend to give a
warning. However, this is not something compilers are required to do.


> More generally, the use of unsigned tends to hide errors. Consider
> functions like std::vector::resize. Most of the time, the parameter
> will be the result of an expression. If some of the input to the
> expression has an unexpected value, and I've forgotten to check it,
> the results may end up negative. The *real* results. If I'm
> calculating with signed values, I can, of course, check this before
> hand. But whatever I do, nothing prevents me from passing this
> negative result to std::vector::resize, because the negative value
> will silently be converted to some positive value. Typically, the
> resulting positive value will be large enough to cause a bad_alloc
> exception on smaller machines. But if I compile in 64 bit mode on the
> machine I'm on now, all that will happen is that I'll use an awful lot
> of memory, the machine will thrash a little (because I've only got 4
> Gig of real memory, and my one little process is taking it all), and
> the program will continue running.
>
> This is a real problem, and there is really no excuse for using
> unsigned types in such interfaces.

This is a valid point.

Why did all the experts decide to converge on my posting? :)

Well, actually, I appreciated that. :)

"I guess we're not in Kansas, anymore." :)

std::vector::resize takes a size_type parameter, so couldn't this be
defined, in an implementation, to be a signed integer?


> > Like I mentioned in the other reply, compilers usually give a
> > warning for such conversions.
>
> Such warnings would pretty much render the compiler useless unless you
> turned them off. Do you really want a warning for:
>
> std::vector< int > v ;
> v.resize( 0 ) ;
>
> [...]

I tested this, now.

Actually, they have done it quite clever, in this case. It only warns for
_change of sign_, not if the number is zero.


To demonstrate:

vector<int> v;

vector<int>::size_type n=-1; // Warning given here (change of sign, as a
result of the conversion)

v.resize(n); // Danger, red alert! :) This gives an address exception here
(invalid access), due to it trying to make the vector store 4G with ints...

v.resize(-1); // Warning given here (same as above)

v.resize(0); // Fine - no warning.


> > A compiler _might_ be able to produce the same code. If it realizes
> > that (signed) (i>=0 && i<10) is the same as (unsigned) (i<10).
>
> It's not that difficult. I've worked on compilers which did it. It's
> a common enough idiom that it's worth checking for.

I understand.


> > I didn't actually think of this.
>
> > It may be unresonable to expect of a compiler, thought. This is a
> > special case.
>
> It's a very common special case, however. Which makes it worth doing.

Yes. But as you can see from the posting, the compilers I tested it on,
didn't do it.


> > The following is the unsigned version (only Intel C++ is shown, the
> > other one is the same way):
>
> > 12: if(i<10)
> > 00401143 mov eax,dword ptr [i]
> > 00401146 cmp eax,0Ah // i<10?
> > 00401149 jae f+15h (00401155) // jump (if above or
equal)
> > (unsigned values)
> > 13: a=10;
> > 0040114B mov dword ptr [a (00428be4)],0Ah
>
> > As you can see, you save a jump.
>
> There's regression, then, because the Intel PL/M compilers of the late
> 1970's did it better.
>
> > In today's deeply pipelined processors, a conditional jump can
> > actually be quite costly, as you risk a branch-misprediction, so it
> > can be several times slower, than if no branch was taken.

By the way, I didn't really think of that there could be compiler writers
around here. I'm not used to that. :)


> Correct. This is why any good compiler will try and eliminate the
> jump if possible. Depending on what you do in the if, it is often
> possible to eliminate all of them. As I said, the Intel compilers
> have been good at this in the past. I'm both surprised and
> disappointed that they don't do better.

Well, then I know that it would be possible for compilers to do.

Pete Becker also pointed this out, in the compilers he has experience with.


Nevertheless, if using unsigned values tend to be dangerous (I'll study
this), then, well, to put it this way, getting the wrong answer fast is
never a bargain. :)


> > You asked where the efficiency argument comes into play. Here it is.
>
> > As is shown, neither of the compilers I tried this with, was able to
> > produce the unsigned version. I don't think one can expect it,
> > either, since it's a special case.

> The compiler I worked on in the late 80's did it. I know that the old
> Intel PL/M compilers did some special optimizations to avoid jumps in
> the late 70's, but I don't know if this was one of them.

I haven't worked on compilers, but I've co-written an ARM-assembler (the
later models are called StrongARM) for the Archimedes/RiscPC computers, so I
was aware of the possible optimizations using unsigned could do.

However, like you mention, a compiler could detect this, and do the same for
signed.

One really nice thing about the ARM processor (Acorn RISC Machine) is that
all instructions could be conditionally exceuted (the branch would just be
like the other instructions). This means you could do things like this:

CMP R0,#1
CMPEQ R1,#2
MOVEQ R2,#10 // if(a==1 && b==2) c=10;

:)

That could be done, without any branching. :)

That's just three cycles (one per instruction, regardless of if it's
executed or not).


The same concept are in the new Intel Itanium processors (predicates).


> (I think
> that part of their optimizations were due to the fact that PL/M didn't
> short-circuit the evaluation. Apparently, the authors of the C
> compiler missed the fact that in some cases, the second part of the
> expression has no side effects, and it is cheaper to evaluate the
> entire expression than to have the two jumps.)

Exactly. That's what is done in the assembly-example above, here.


> Which, of course, leaves open the question of whether this has ever
> been a bottleneck in real code. (Most of the time, when your running
> that close to the limits, all bounds checking goes out the door.)

My point was that, if it doesn't cost anything, otherwise, and it could
actually ensure things like unsignedness, then it could be useful. However,
because there are implicit conversions from signed (which may or may not be
warned against, depending on the compiler), well, then that's something to
consider.


Regards,

Terje Slettebo

tslettebo at chello dot no.

Terje Slettebø

ulæst,
28. nov. 2001, 08.03.2328.11.2001
til
"Mark Wilden" <ma...@mwilden.com> wrote in message
news:u08ak3i...@news.supernews.com...

> "James Kanze" <ka...@gabi-soft.de> wrote in message
> news:d6651fb6.01112...@posting.google.com...
> >
> > > I use unsigned integers when it makes no sense for a value to be
> > > negative (this includes most for-loops). This is similar to using
> > > integral types instead of floating types when I'm dealing with whole
> > > numbers--the practice simply represents my intent more accurately.
> >
> > I agree in theory, and did this for a long time myself. In the end,
> > however, the implicit conversions mean that you've just added another
> > possible error that you can't effectively check for.
>
> I would just _love_ to have a good reason not to use unsigneds as a rule
of
> thumb for counts because of the extra typing and horizontal scrolling. :)

You could use e.g.:

typedef unsigned int uint;
....
for(uint i=0;i<x;++i)
....

(Note that "unsigned", by itself, is non-standard.)

Opps, did I push in the wrong direction, now? :) You wanted reasons for
_not_ using unsigned, right...

:)

Well, for that, I refer to the other posters.

Myself, I'm contemplating this, myself. I, too, have tended to use it, as,
like you say, it expresses the intent in the code (that the value can't be
negative).


Regards,

Terje Slettebo

tslettebo at chello dot no.

Gerhard Menzl

ulæst,
28. nov. 2001, 08.18.1028.11.2001
til
Mark Wilden wrote:

> I would just _love_ to have a good reason not to use unsigneds as a rule
> of thumb for counts because of the extra typing and horizontal scrolling.
> :)
>
> But I don't see what possible error a usage like this could lead to:
>
> for (unsigned i = 0; i < x; ++i)
> // ...

None, until a hasty maintenance programmer decides to invert the loop
order:

for (unsigned i = x - 1; i >= 0; --i)
// ...

Depending upon what i is used for inside the loop, this will either
demonstrate the concept of eternity or get you deep into undefined
territory. :-)

> To me, using an int here is just wrong, because an int is signed, and
> signedness is semantically meaningless for i. I'd say the same about
> anything that counts.

Even if you are counting down?

Gerhard Menzl

Terje Slettebø

ulæst,
28. nov. 2001, 15.25.1128.11.2001
til
"Gerhard Menzl" <gerhar...@sea.ericsson.se> wrote in message
news:3C04AAC4...@sea.ericsson.se...

> Mark Wilden wrote:
>
> > I would just _love_ to have a good reason not to use unsigneds as a
rule
> > of thumb for counts because of the extra typing and horizontal
scrolling.
> > :)
> >
> > But I don't see what possible error a usage like this could lead to:
> >
> > for (unsigned i = 0; i < x; ++i)
> > // ...
>
> None, until a hasty maintenance programmer decides to invert the loop
> order:
>
> for (unsigned i = x - 1; i >= 0; --i)
> // ...
>
> Depending upon what i is used for inside the loop, this will either
> demonstrate the concept of eternity or get you deep into undefined
> territory. :-)

Some compilers will warn against this one (Intel C++ does, but VC++
doesn't).

On the Intel C++ compiler, I get:

for (unsigned i = x - 1; i >= 0; --i) // warning #186: pointless comparison
of unsigned integer with zero


> > To me, using an int here is just wrong, because an int is signed, and
> > signedness is semantically meaningless for i. I'd say the same about
> > anything that counts.
>
> Even if you are counting down?

The bottom line is, if you get warnings for conversions from signed (more
specifically, for conversions where the result may be wrong, like a
sign-change), and for operations that give no meaning (like comparing for
greater or equal to zero), then this appears to be safe.

As I mentioned in another posting, implicit conversions between the built-in
types regards more than just signed and unsigned, and can give loss of
precision, or overflow or underflow, when converting between different
types.

For example, the following gives no warning, even on the highest
warning-level, on the Intel C++ compiler:

double d;
char c;
....
c=d;

This doesn't mean there's a problem with using types with such implicit
conversions. It just means there are legal conversions, that may give a
wrong answer. This doesn't just pertain to signed and unsigned, but with
these, I do actually get warnings, unlike the last code example.


I will consider this more, though.


Regards,

Terje Slettebo

tslettebo at chello dot no.

Sungbom Kim

ulæst,
28. nov. 2001, 15.33.0228.11.2001
til
James Kanze wrote:
>
> More generally, the use of unsigned tends to hide errors. Consider
> functions like std::vector::resize. Most of the time, the parameter
> will be the result of an expression. If some of the input to the
> expression has an unexpected value, and I've forgotten to check it,
> the results may end up negative. The *real* results. If I'm
> calculating with signed values, I can, of course, check this before
> hand. But whatever I do, nothing prevents me from passing this
> negative result to std::vector::resize, because the negative value
> will silently be converted to some positive value. [...]

>
> This is a real problem, and there is really no excuse for using
> unsigned types in such interfaces.

I have wondered why std::vector<T>::resize or std::vector<T>::operator[]
takes unsigned integers as their argument, why the Standard made them so.
What would you say about this?
And which would you recommend, signed or unsigned, for such functions
of a user-defined type I'd write from scratch?

> The only times unsigned types are justified in application code is

> when you *want* the defined overflow they provide. [...]
> [...] The are also useful in some system code where you really


> do have to consider *all* of the memory as a single array of so many
> bytes (the implementation of sbrk comes to mind).

--
Sungbom Kim <musi...@bawi.org>

Sungbom Kim

ulæst,
28. nov. 2001, 15.34.3828.11.2001
til
Mark Wilden wrote:
>
> "James Kanze" <ka...@gabi-soft.de> wrote in message
> news:d6651fb6.01112...@posting.google.com...
> >
> > > I use unsigned integers when it makes no sense for a value to be
> > > negative (this includes most for-loops). This is similar to using
> > > integral types instead of floating types when I'm dealing with whole
> > > numbers--the practice simply represents my intent more accurately.
> >
> > I agree in theory, and did this for a long time myself. In the end,
> > however, the implicit conversions mean that you've just added another
> > possible error that you can't effectively check for.
>
> I would just _love_ to have a good reason not to use unsigneds as a rule of
> thumb for counts because of the extra typing and horizontal scrolling. :)
>
> But I don't see what possible error a usage like this could lead to:
>
> for (unsigned i = 0; i < x; ++i)
> // ...

If you use unsigned i in an expression that might have yielded
a negative result, you will make the entire expression unsigned,
thus implicitly converting the result to a positive value.

// print the first ten negative multiples of three
for (unsigned i = 1; i <= 10; ++i)
std::cout << (i * -3) << '\n'; // doesn't work!

You could, of course, change the loop to something like
'for (int i = -3; i >= -30; i -= 3)' in this special case,
but I'm raising a general issue.

--
Sungbom Kim <musi...@bawi.org>

Sungbom Kim

ulæst,
28. nov. 2001, 15.35.1228.11.2001
til
Terje Sletteb=F8 <clcppm...@this.is.invalid> wrote in message
news:<GfxM7.4529$Sa4.6...@news01.chello.no>...

> "James Kanze" <ka...@gabi-soft.de> wrote in message
> news:d6651fb6.01112...@posting.google.com...
> > Because it doesn't work. An unsigned number is always positive.
> > Even when it was initialized with a negative number. This can
> > potentially hide errors.

> Look at the example I gave. It does work.

The fact is that you cannot even test with unsigned arguments if the
caller passed a negative value or not, because the value you get is
already converted to unsigned.

You said the example worked, but when the argument 'i' is passed a
negative value it is the condition 'i<10' and not the 'unsigned'
type that detects it, because small negative integers are implicitly
converted to large positive integers. The condition 'i<10' is not
meant to check for negative values; it just happens to in this case,
by help of the implicit conversion.

If you wanted a larger range (e.g. 0<=i && i<40000), a 'big' negative
value (e.g. -30000) could simply pass the test, on a 16-bit environment.
(This is what I wanted to say in my first reply to your article.)

Mark Wilden

ulæst,
28. nov. 2001, 15.41.2628.11.2001
til
"Terje Sletteb=F8" <clcppm...@this.is.invalid> wrote in message
news:mYZM7.4737$Sa4.6...@news01.chello.no...

> You could use e.g.:
>
> typedef unsigned int uint;

Right, and most projects I've worked on have indeed included uint. But I
don't like using such syntactic sugar, as it increases the dependencies=
on a
(probably global--ugh) header file (the one that defines the typedef).

> (Note that "unsigned", by itself, is non-standard.)

Are you sure about that? Because if I have to write

for (unsigned int i = 0; //...

then I'm switching back to int _right now_. :_)

> Myself, I'm contemplating this, myself. I, too, have tended to use it=
, as,
> like you say, it expresses the intent in the code (that the value can=
't be
> negative).

Exactly. When any programmer sees an unsigned, he knows that part of the
_meaning_ of the variable is that it can't be < 0.

It's compilable documentation.

Mark Wilden

ulæst,
28. nov. 2001, 15.42.0828.11.2001
til
"Gerhard Menzl" <gerhar...@sea.ericsson.se> wrote in message
news:3C04AAC4...@sea.ericsson.se...

> > But I don't see what possible error a usage like this could lead to:


> >
> > for (unsigned i = 0; i < x; ++i)
> > // ...
>
> None, until a hasty maintenance programmer decides to invert the loop
> order:
>
> for (unsigned i = x - 1; i >= 0; --i)
> // ...

I refuse to change my coding style to account for such stupidity. I would
change companies first. :)

> > To me, using an int here is just wrong, because an int is signed, and
> > signedness is semantically meaningless for i. I'd say the same about
> > anything that counts.
>
> Even if you are counting down?

Of course. -1 has no meaning whether you're counting up or counting down.
There may be specialized definitions of the word "count" that allow negative
values, but I'm using the commonplace definition where they would make no
sense. You can't have -35 chickens (not even if you owed someone 35
chickens).

Terje Slettebø

ulæst,
28. nov. 2001, 17.08.4528.11.2001
til
"James Kanze" <ka...@gabi-soft.de> wrote in message
news:d6651fb6.01112...@posting.google.com...
> Terje Slettebø <clcppm...@this.is.invalid> wrote in message
> news:<jBvM7.4518$Sa4.6...@news01.chello.no>...
> > "Sungbom Kim" <musi...@bawi.org> wrote in message
> > news:3C01A154...@bawi.org...
>
> > To take the example of char. Signed char gives the range -128 to
> > 127. Unsigned char gives 0 to 255. Not useful? I'd definitely think
> > it's useful. You just got twice as large positive range. The same
> > goes for all the integers.
>
> The problem is: if 128 is not sufficient today, then 256 will not be
> sufficient tomorrow. If 128 isn't sufficient, then use short.
>
> > If you used a signed char to represent an 8-bit char, it wouldn't
> > fit.
>
> This is a *very* real problem. However, the type for characters in
> C++ is char, not unsigned char, and there isn't much you can do about
> it. (String literals have type char const[], for example.) It's a
> real pain when some of your daily character values have negative
> values, and you have to continually cast to unsigned char to see them,
> but there isn't much you can do about it.

There's often an option on compilers, whether or not to treat char as signed
or unsigned. This is course not portable, though.


> > If you represent unsigned values with unsigned integers, it's
> > perfectly safe. It's not just safe, it can be an advantage, because
> > you specify a more specific type (the way an UDT is a more specific
> > type), and the program enforces it.
>
> If you reread what Bjarne wrote, what he says is that because of

I haven't actually read it in the first place. :) I only read the quote
given here.


> implicit type conversions, the program *doesn't* enforce it. It just
> gives the impression that it does. So you have a choice: signed, and
> a runtime check, or unsigned, and no check what so ever.

I'll investigate this, and give a reply afterwards. I have the book.


> > As an example:
>
> > int i=-1;
> > unsigned int j=i; // No good as conversion; j will be 255, not 1.
>
> More likely j will be a lot larger than 255. According to the
> standard, the results are implementation defined, and may trap. In
> practice, you will generally get INT_MIN.

Opps, I was thinking of char, here. A direct bit-mapping (using 32-bit ints)
would give 0xffffffff, not 255.


> Have you actually measured the difference in a real program, with a
> modern compiler? And found it to be a bottleneck in your code?

No.

But I did give concrete assembler-listings in a posting in this thread,
showing the difference.


> Compilers generally know what the machine instructions do. The
> compile I worked on (almost 15 years ago) had no trouble optimizing
> the comparison with signed, and generated exactly the same code in
> both cases.

Well, my point with giving the actual assembler-output, using two different
compilers (VC++ and Intel C++), was to test this hypothesis (which also the
other poster mentioned). At least for those compilers, the result was that
neither compiler optimized away the check for less than zero, so they
generated different code.


> > > You also have to mind that variables of unsigned integral types
> > > are just *interpreted* as non-negative values (via modulo
> > > operation);
>
> Actually, there's a real reason to use unsigned hidden in this
> statement. Overflow is a defined operation in unsigned arithmetic;

But how can you check for integer overflow, in C++?

Or is it just defined, in the way that the top bit disappears?


> it's undefined behavior in signed arithmetic. So in the few cases
> where defined overflow is desired (calculating hash values, for
> example), unsigned must be used. A somewhat weaker constraint
> involves integral division and modulo (the / and % operators), whose
> results are implementation defined for negative values.

> > What happens is that the bits are interpreted as unsigned, rather


> > than signed values, which gives a different result.
>
> That is *not* what happens, although on many hardware, the results are
> the same as what does happen, and the compiler optimizes to exploit
> this fact. The results of converting a negative value to an unsigned
> are defined by the standard as (UINT_MAX + 1) + negative_value.

Ok. :)

I just tested it on the compiler. I didn't actually consult the standard,
here.

I guess I should have known better than to try to get away with that, in a
newsgroup full of C++ experts and compiler writers. :)

Well, it's really a pleasure to be here. :)


> > No operation is actually performed on the value.
>
> On most machines.

I understand.


> > If you mean, by ensuring positiveness, that you can't do:
>
> > unsigned int a=-1; // a won't be 1, but UINT_MAX (as you show in your
> > example)
>
> > then I agree with you.
>
> Then we agree.
>
> Whatever the architecture, a will *not* be equal to -1, which is what
> the user wanted. But there is no compile time error. And it is
> impossible to verify at runtime that the value isn't what was wanted,
> because it got changed. This is precisely the argument against
> unsigned values.

I'll consult Bjarne Stroustrup's book, and the standard, and deliberate on
this.

I'll give a feedback when I've done it.

Thanks for the well-informed feedback, everybody.


> But the reason it is ensured positive isn't that the user can't
> accidentally pass a negative value; it is that if the user does so, it
> gets implicitly (and silently) converted to some incorrect positive
> value.

I guess this has something to do with the type-system of C++, regarding the
built-in types. Some of it may be for legacy reasons.

There are quite a few conversions, including the ones here, from signed to
unsigned, that can easily lead to wrong answers, as you point out, yet the
conversion is legal.

The same goes for other conversions, where e.g. double can be converted to
int, and even to, of all things, char. :)


> > Whether a conversion from a signed, to an unsigned type, yield
> > correct values, is an entirely different matter.
>
> Unless, of course, you want the program to give the correct results.

Yeah. :)

Or for the compiler to at least give a warning, if this is attempted.


> The entire gist of your argument boils down that if you know the
> number is positive, using unsigned values is safe. I don't think that
> anyone could argue about that, but your conclusion rests on the
> somewhat shakey assumption that no client code could ever make the
> mistake of accidentally passing a negative value.

Yes.

Conversion from signed to unsigned is legal, and compiled aren't required to
give a warning about it (although many do).

So, it's a type-issue. Since it can be implicitely converted to the other
one.

But then, the same can happen if you try to convert a large double to a
char, which is also legal.


I'll think about, and stufy, all this, and get back to you about it.


Regards,

Terje Slettebo

tslettebo at chello dot no.

Martin Aupperle

ulæst,
28. nov. 2001, 17.11.1828.11.2001
til
On 26 Nov 2001 10:53:48 -0500, Sungbom Kim <musi...@bawi.org> wrote:

>Terje Slettebø wrote:
>>
>Bjarne Stroustrup says in The C++ Programming Language, 4.4:
>
> The <unsigned> integer types are ideal for uses that treat storage
> as a bit array. Using an <unsigned> instead of an <int> to gain
> one more bit to represent positive integers is almost never a good
> idea. Attempts to ensure that some values are positive by declaring
> variables <unsigned> will typically be defeated by the implicit
> conversion rules.
>
>Why would he have said so?
>

I never really understood what he meant by "defeated by the implicit
conversion rules". Can you give an explanation?

BTW, I use unsigned ints often in my programs because size_t is used
often in the STL.

------------------------------------------------
Martin Aupperle
MikeAlpha@NoSpam_csi.com
(remove NoSpam_)
------------------------------------------------

Francis Glassborow

ulæst,
28. nov. 2001, 17.23.0128.11.2001
til
In article <BLZM7.4736$Sa4.6...@news01.chello.no>, Terje Slettebø
<clcppm...@this.is.invalid> writes

>My point was that, if it doesn't cost anything, otherwise, and it could
>actually ensure things like unsignedness, then it could be useful. However,
>because there are implicit conversions from signed (which may or may not be
>warned against, depending on the compiler), well, then that's something to
>consider.

Rightly or wrongly most programmers switch off the warnings about
conversions between integer types because a great deal of code will
generate a veritable flood of such warnings and thereby hide other
warnings. Note that int->unsigned int deserves a warning because of
possible conversion errors but so does unsigned int-> int (possible
narrowing and irrecoverable loss of data). Consistently using int
everywhere avoids these warnings. I understand the conceptual argument,
but favour the pragmatic one.


--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Mark Wilden

ulæst,
29. nov. 2001, 03.30.5329.11.2001
til
"Sungbom Kim" <musi...@bawi.org> wrote in message
news:3C04FF66...@bawi.org...

> >
> > But I don't see what possible error a usage like this could lead to:
> >
> > for (unsigned i = 0; i < x; ++i)
> > // ...
>
> If you use unsigned i in an expression that might have yielded
> a negative result, you will make the entire expression unsigned,
> thus implicitly converting the result to a positive value.

But this applies to all usage of unsigned, right? I was only referring to
the usage above.

> // print the first ten negative multiples of three
> for (unsigned i = 1; i <= 10; ++i)
> std::cout << (i * -3) << '\n'; // doesn't work!

Clearly, it would be insane to use an unsigned value to compute a signed
value in this manner.

> You could, of course, change the loop to something like
> 'for (int i = -3; i >= -30; i -= 3)' in this special case,
> but I'm raising a general issue.

I feel your example was a very special case, indeed. Far more general, in my
opinion, is to use a loop counter to iterate through an array, and not
perform any other manipulation of the value.

Terje Slettebø

ulæst,
29. nov. 2001, 03.55.0929.11.2001
til
"Martin Aupperle" <Martin....@quasar-gmbh.de> wrote in message
news:3c04e3c5...@News.CIS.DFN.De...

> On 26 Nov 2001 10:53:48 -0500, Sungbom Kim <musi...@bawi.org> wrote:
>
> >Terje Slettebø wrote:
> >>
> >Bjarne Stroustrup says in The C++ Programming Language, 4.4:
> >
> > The <unsigned> integer types are ideal for uses that treat storage
> > as a bit array. Using an <unsigned> instead of an <int> to gain
> > one more bit to represent positive integers is almost never a good
> > idea. Attempts to ensure that some values are positive by declaring
> > variables <unsigned> will typically be defeated by the implicit
> > conversion rules.
> >
> >Why would he have said so?
> >
>
> I never really understood what he meant by "defeated by the implicit
> conversion rules". Can you give an explanation?

I think what is meant is that there's an implicit conversion from signed to
unsigned integer, and the compiler isn't required to give a warning about it
(although some may do).

For example:

int main()
{
f(-1);
}

void f(unsigned int i)
{
// i is unsigned, but not e.g. abs(i)
}


Regards,

Terje Slettebo

Terje Slettebø

ulæst,
29. nov. 2001, 06.48.5529.11.2001
til
"Sungbom Kim" <musi...@bawi.org> wrote in message
news:3C0503D1...@bawi.org...

> Terje Sletteb=F8 <clcppm...@this.is.invalid> wrote in message
> news:<GfxM7.4529$Sa4.6...@news01.chello.no>...
> > "James Kanze" <ka...@gabi-soft.de> wrote in message
> > news:d6651fb6.01112...@posting.google.com...
> > > Because it doesn't work. An unsigned number is always positive.
> > > Even when it was initialized with a negative number. This can
> > > potentially hide errors.
>
> > Look at the example I gave. It does work.
>
> The fact is that you cannot even test with unsigned arguments if the
> caller passed a negative value or not, because the value you get is
> already converted to unsigned.

Yes, I know. :)

I do get a warning, if a negative constant is passed. But I just found, like
I said in another posting, that it doesn't do any checks when passing a
signed variable.

My intent when saying that it works, is that you're guaranteed that the
unsigned value is positive.

If it's the right positive value, is another issue. :)

That's why I've said I'll study this some more, and reconsider, before
giving feedback about what I think.


Regards,

Terje Slettebo

tslettebo at chello dot no.

Terje Slettebø

ulæst,
29. nov. 2001, 13.50.1929.11.2001
til
"Mark Wilden" <ma...@mwilden.com> wrote in message
news:u0ad46m...@news.supernews.com...

> "Terje Sletteb=F8" <clcppm...@this.is.invalid> wrote in message
> news:mYZM7.4737$Sa4.6...@news01.chello.no...

Hi.

> > You could use e.g.:
> >
> > typedef unsigned int uint;
>
> Right, and most projects I've worked on have indeed included uint. But I
> don't like using such syntactic sugar, as it increases the dependencies=
> on a
> (probably global--ugh) header file (the one that defines the typedef).

I understand.

I find them easier to read (and write), when they are shorter, though.

It's similar to "using"-declarations, and other typedefs.


I'm agreeing with you in that one shouldn't redefine things that shouldn't
be redefined, such as Microsoft's insistance on redefining the built-in
types to UPPER CASE versions, which are defined to the lower case versions.

This makes it harder to read, as you have to check the typedefs, to find out
what they are, and it introduces a needless extra level of indirection.
Essentially, they make another language of it, by using all these typedef's
and #define's (including defining redefining const as CONST, of all things).
In addition, I think it looks ugly, because they redefine big parts of the
language, to something that doesn't look like C++.

I assume they do this for legacy reasons, to be able to use the same library
on different platforms (like 16 and 32 bit).

However, in the case of uint, it's just a shorthand for unsigned int. (Same
with the other integer types. And I don't use UINT. :) ).

So, as mentioned, for me, that actually makes it easier to read (and write),
because it's shorter.

It does mean you have to have a typedef somewhere, yes.

However, I tend to have a small header-file with such things, that I
include, anyway.

This also enables me to do things like (on the VC++ system):

--- Header.h ---

#define pragmaStr warning(disable: ...)

--- OtherFile.h (or .cpp) ---

#include "Header.h"

#pragma pragmaStr


Thus, I can change the warning reporting (like ignoring a warning), by
changing just _one_ place, without having to edit all the files.

I prefer including a header like this, to writing long names for the
built-in types.


> > (Note that "unsigned", by itself, is non-standard.)
>
> Are you sure about that? Because if I have to write

No. I meant I've read it, but I've not found it in the C++ draft standard,
now.

Can anybody else tell what the case is, here?


> for (unsigned int i = 0; //...
>
> then I'm switching back to int _right now_. :_)
>
> > Myself, I'm contemplating this, myself. I, too, have tended to use it=
> , as,
> > like you say, it expresses the intent in the code (that the value can=
> 't be
> > negative).
>
> Exactly. When any programmer sees an unsigned, he knows that part of the
> _meaning_ of the variable is that it can't be < 0.
>
> It's compilable documentation.

Yes.


Regards,

Terje Slettebo

tslettebo at chello dot no.

Terje Slettebø

ulæst,
29. nov. 2001, 13.50.5929.11.2001
til
"Sungbom Kim" <musi...@bawi.org> wrote in message
news:3C04FF66...@bawi.org...

> Mark Wilden wrote:
> >
> > "James Kanze" <ka...@gabi-soft.de> wrote in message
> > news:d6651fb6.01112...@posting.google.com...
> > >
> > But I don't see what possible error a usage like this could lead to:
> >
> > for (unsigned i = 0; i < x; ++i)
> > // ...
>
> If you use unsigned i in an expression that might have yielded
> a negative result, you will make the entire expression unsigned,
> thus implicitly converting the result to a positive value.
>
> // print the first ten negative multiples of three
> for (unsigned i = 1; i <= 10; ++i)
> std::cout << (i * -3) << '\n'; // doesn't work!

If you're using an unsigned variable in an expression which may yield a
negative value, you may be better off with a signed variable, yes. (Or you
have to convert it to signed, first.)

As the expression goes: Nothing unexpected happens, unless, of course, your
expectations are wrong.

:)


Regards,

Terje Slettebo

tslettebo at chello dot no.

Terje Slettebø

ulæst,
29. nov. 2001, 17.53.5729.11.2001
til
"Francis Glassborow" <francis.g...@ntlworld.com> wrote in message
news:m7JzLmAg...@robinton.ntlworld.com...

> In article <BLZM7.4736$Sa4.6...@news01.chello.no>, Terje Slettebø
> <clcppm...@this.is.invalid> writes
>>
>> Rightly or wrongly most programmers switch off the warnings about
>> conversions between integer types because a great deal of code will
>> generate a veritable flood of such warnings and thereby hide other
>> warnings. Note that int->unsigned int deserves a warning because of
>> possible conversion errors but so does unsigned int-> int (possible
>> narrowing and irrecoverable loss of data). Consistently using int
>> everywhere avoids these warnings. I understand the conceptual argument,
>> but favour the pragmatic one.

Terje Slettebo:

>In my opinion, we're more protected against problems in converting from
>signed to unsigned, than other conversions (which give no warning), like
>narrowing conversions, including from floating point types to integer
types.

I just now found that it only checks if _constants_ sent to unsigned types,
changes the sign, not signed variables (where it can't know if it possibly
changes the sign), so it means one isn't that protected for this, after all.

E.g.:

unsigned int i;
int j;
....
i=j; // No warning


Regards

Terje Slettebo

tslettebo at chello dot no.

Terje Slettebø

ulæst,
29. nov. 2001, 17.55.1229.11.2001
til
"Francis Glassborow" <francis.g...@ntlworld.com> wrote in message
news:m7JzLmAg...@robinton.ntlworld.com...
> In article <BLZM7.4736$Sa4.6...@news01.chello.no>, Terje Slettebø
> <clcppm...@this.is.invalid> writes
> >My point was that, if it doesn't cost anything, otherwise, and it could
> >actually ensure things like unsignedness, then it could be useful.
However,
> >because there are implicit conversions from signed (which may or may not
be
> >warned against, depending on the compiler), well, then that's something
to
> >consider.
>
> Rightly or wrongly most programmers switch off the warnings about
> conversions between integer types because a great deal of code will
> generate a veritable flood of such warnings and thereby hide other
> warnings. Note that int->unsigned int deserves a warning because of
> possible conversion errors but so does unsigned int-> int (possible
> narrowing and irrecoverable loss of data). Consistently using int
> everywhere avoids these warnings. I understand the conceptual argument,
> but favour the pragmatic one.

On another message to you in this thread, I mentioned that at least on Intel
C++, this is handled by only giving a warning in the case of a conversion
_changing the sign_, when converting from signed to unsigned.

I run the warnings at the highest level, to get all warnings, and
selectively disable warnings. This is, however, one warning I haven't needed
to disable, because when it comes, it tells about a real problem, so it's
useful.

In my opinion, we're more protected against problems in converting from
signed to unsigned, than other conversions (which give no warning), like
narrowing conversions, including from floating point types to integer types.

The conversion from unsigned to signed is also such a narrowing conversion,
only in this case it's only a bit.

I take a pragmatic approach to this, too.

The pragmatic approach have given me warnings if incorrect values were sent
to functions, like ones taking unsigned values, without this being
explicitely checked with a range-check in the code.

In other words, what I'm doing is to use stronger typing to ensure
correctness (unsigned is a different type than signed).

Using a more specific type (like unsigned rather than signed, when the
values are unsigned), and this way let the static type-system ensure
correctness, is a well-regarded C++ way, in general.

Another thing is that in this case, because of conversion rules, it's
compiler-dependent whether or not you get warnings.


Regards,

Terje Slettebo

tslettebo at chello dot no.

Gerhard Menzl

ulæst,
29. nov. 2001, 17.58.0229.11.2001
til
Mark Wilden wrote:

> > > But I don't see what possible error a usage like this could lead to:
> > >
> > > for (unsigned i = 0; i < x; ++i)
> > > // ...
> >
> > None, until a hasty maintenance programmer decides to invert the loop
> > order:
> >
> > for (unsigned i = x - 1; i >= 0; --i)
> > // ...
>
> I refuse to change my coding style to account for such stupidity. I would
> change companies first. :)

You must be a real job hopper then. :-)

Seriously, what I wanted to point out is that using unsigned integers
for loop counters can make it unnecessarily awkward to iterate in
descending index order.

> > > To me, using an int here is just wrong, because an int is signed, and
> > > signedness is semantically meaningless for i. I'd say the same about
> > > anything that counts.
> >
> > Even if you are counting down?
>
> Of course. -1 has no meaning whether you're counting up or counting down.
> There may be specialized definitions of the word "count" that allow
> negative values, but I'm using the commonplace definition where they would
> make no sense. You can't have -35 chickens (not even if you owed someone
> 35 chickens).

I don't think agro-economical conventions can be applied directly to
software engineering. You wouldn't call the chicken in the leftmost box
the 0th chicken, for example.

We routinely use an index of one past the last element of an array
(although we may not access what lurks there), so there is nothing wrong
in principle with forming an index of one before the first element (the
0th chicken, if you prefer) for comparison. That this is not possible
with pointers is an arbitrary convention.

Gerhard Menzl

Mark Wilden

ulæst,
30. nov. 2001, 07.33.4130.11.2001
til
"Gerhard Menzl" <gerhar...@sea.ericsson.se> wrote in message
news:3C05F728...@sea.ericsson.se...

> > >
> > > for (unsigned i = x - 1; i >= 0; --i)
> > > // ...
> >
> > I refuse to change my coding style to account for such stupidity. I
would
> > change companies first. :)
>
> You must be a real job hopper then. :-)

You know, I hear these kinds of horror stories, and, while I don't think
I've been gifted with especially intelligent C++ coworkers, I thank my lucky
stars that they haven't been as bad as that! :)

> Seriously, what I wanted to point out is that using unsigned integers
> for loop counters can make it unnecessarily awkward to iterate in
> descending index order.

Well, sure. I wasn't really proposing an absolute rule that all loop
counters should be unsigned. I meant that in the code I posted, I couldn't
see a bug potential. I agree that if you're doing something different, like
decrementing backwards, or using the loop counter for more than looping,
then unsigned sounds like a bad choice. In the case under discussion, of
course, the bug introduced is trivial to test for and to fix.

>> You can't have -35 chickens (not even if you owed someone
> > 35 chickens).
>
> I don't think agro-economical conventions can be applied directly to
> software engineering.

:)

> You wouldn't call the chicken in the leftmost box the 0th chicken, for
example.

No, but while the treatment of ordinals is different in C++ than in real
life, I don't the the concept of counting is different.

> We routinely use an index of one past the last element of an array
> (although we may not access what lurks there), so there is nothing wrong
> in principle with forming an index of one before the first element (the
> 0th chicken, if you prefer) for comparison. That this is not possible
> with pointers is an arbitrary convention.

Sorry, I don't see what this has to do with counts. A loop "counter" isn't a
count--it's an index, hence there are indeed situations where an int is
appropriate.

You simply cannot have a negative number of chickens, so I feel making
nChickens an int is misleading. Now, for implementation reasons, you may in
fact store your "number of chickens" as a negative number. You might make
this optimization, for example, so that you can easily track the quantity
"number of chickens I own minus the number of chickens I owe." This really
isn't the same thing as a count of chickens, and I think calling such a
quantity "nChickens" would be misleading.

And no, I don't know how I got on to chickens. :)

Terje Slettebø

ulæst,
30. nov. 2001, 07.35.5930.11.2001
til
"Terje Slettebø" <clcppm...@this.is.invalid> wrote in message
news:eoJM7.4570$Sa4.6...@news01.chello.no...

> "Sungbom Kim" <musi...@bawi.org> wrote in message
> news:3C02E5A2...@bawi.org...
> > David Bradley wrote:
> > >
> > > James Kanze wrote:
> > >
> > > > The problem is, you can know that the value you got isn't negative,
> > > > but you can't know that the caller didn't try to pass you a
negative.
> > >
> > > You can't know but the caller should get a warning from the compiler
> > > complaining about the passing of a signed to an unsigned. Isn't that
> > > worth something? If I'm implementing a function and a negative number
> > > makes no sense, doesn't it make more sense to let the compiler tell my
> > > caller that he's doing something potentially bad, rather than waiting
> > > for a runtime assert/error.
> >
> > I don't get any warning under gcc 2.95.4 (even with -Wall):

Terje Slettebo:

> It does give a warning in Intel C++ and VC++.

> > void foo(unsigned);
> >
> > int main(void)
> > {
> > int x = -1;
> > foo(x);
> > }

Actually, just to set this one straight, I found it _doesn't_ give a warning
in this case, after all. I knew that it gave a warning, if you passed a
known negative constant, to an unsigned parameter (like "foo(-1)", here), as
then it knows the conversion results in a change of sign. However, it
doesn't give a warning if you just pass a signed type.


The same goes for the following posting:

Pete Becker <peteb...@acm.org> wrote in message

news:<3C03DAD0...@acm.org>...


> Terje Slettebø wrote:
> >
> > "Pete Becker" <peteb...@acm.org> wrote in message

> > news:3C02F59E...@acm.org...
> > > David Bradley wrote:
> > > >
> > > > James Kanze wrote:
> > > >
> > > > > The problem is, you can know that the value you got isn't
negative,
> > > > > but you can't know that the caller didn't try to pass you a
negative.
> > > >
> > > > You can't know but the caller should get a warning from the compiler
> > > > complaining about the passing of a signed to an unsigned.
> > > >
> > >
> > > The conversion from signed to unsigned is well-defined and useful. How
> > > can the compiler know whether passing a signed value is a mistake or
> > > deliberate?
> >

Terje Slettebo:

> > At least in some compilers, you can get a warning, for this.

> Yes, some compilers are presumptious. <g>

Well, since it turns out they don't give warnings for this, after all, it
turns out they aren't presumtious, after all, then.


Regards,

Terje Slettebo

Dave Harris

ulæst,
30. nov. 2001, 07.36.2730.11.2001
til
musi...@bawi.org (Sungbom Kim) wrote (abridged):

> I have wondered why std::vector<T>::resize or std::vector<T>::operator[]
> takes unsigned integers as their argument, why the Standard made them
> so.

It uses size_t. Size_t is the type which is guaranteed big enough to store
the sizeof any object. We want to use that type for std::vector<char>
otherwise we'll have an unnecessary restriction on the maximum size of a
vector.

Size_t is often an unsigned type because it needs to be at least big
enough to measure physical memory. Physical memory often comes in sizes
like 64k, or 4Gb, and a signed type would either be too small or extremely
wasteful.

That said, vector's use of unsigned types can cause problems. Eg:

int sum_first( int count, const std::vector<int> &v ) {
int sum = 0;
int lim = std::min( v.size(), count );
for (int i = 0; i < lim; ++i)
sum += v[i];
return sum;
}

will fail to compile because std::min() likes both its arguments to have
the same type, and vector didn't use int.

One way to fix it is to change "int count" to "size_t count". In this way
an unsigned type can propagate through a program. They are infectious, a
bit like const-correctness. I see this as another reason not to use
unsigned casually.

Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
bran...@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."

Dave Harris

ulæst,
30. nov. 2001, 10.23.4630.11.2001
til
ma...@mwilden.com (Mark Wilden) wrote (abridged):

> You simply cannot have a negative number of chickens, so I feel making
> nChickens an int is misleading. Now, for implementation reasons, you
> may in fact store your "number of chickens" as a negative number.
> You might make this optimization, for example, so that you can
> easily track the quantity "number of chickens I own minus the number
> of chickens I owe." This really isn't the same thing as a count
> of chickens, and I think calling such a quantity "nChickens" would
> be misleading.

Agreed. However, if we use unsigned only for chicken-counts that are
always >= 0, then in C++ the type of the difference of two chicken-counts
will also be unsigned, even though it may be negative.

In other words, when we declare a type to be unsigned we are saying more
than "this value will always be >= 0". We are saying something about its
entire algebra. We are asking for a different kind of mathematics. In
effect we're asking for modulo-arithmetic instead of normal arithmetic.
It's about operations, not individual values.

What we want for chickens is a way to say, "This value is an integer which
is always >= 0." I agree this a reasonable thing to want. C++ does not
have a good way to say it. C++ only lets us ask for modulo-arithmetic.
Modulo-arithmetic is not suitable for counting chickens. We shouldn't use
it for that. We shouldn't declare chicken-counts as unsigned int.

Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
bran...@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

ulæst,
30. nov. 2001, 12.40.4430.11.2001
til
Terje Sletteb <clcppm...@this.is.invalid> wrote in message
news:<sZXM7.4733$Sa4.6...@news01.chello.no>...

[...]


> > Have you actually measured the difference in a real program, with
> > a modern compiler? And found it to be a bottleneck in your code?

> No.

> But I did give concrete assembler-listings in a posting in this
> thread, showing the difference.

But did it result in a measurable difference in the execution time of
a real program. If not, who cares?

[...]


> But how can you check for integer overflow, in C++?

In in advance, by verifying that the operands are in a range that
won't cause overflow. A C++ compiler *could* generate code to check;
in the 80x86 architecture, there is (or at least was) an instruction
especially designed for this, INTO, which would trigger a software
interrupt if the overflow bit was set. IMHO, on decent hardware, this
would be the normal case, and you'd have to take special steps to
avoid it, but the only hardware I've heard about where this was
actually the case was a machine designed by Nikolaus Wirth,
expressedly to run Oberlin on. A good compiler could theoretically
annotate the code enough to detect the cases where checking was
necessary, but compile times would doubtlessly soar if it did so.

Still, one can dream.

--
James Kanze mailto:ka...@gabi-soft.de
Beratung in objektorientierer Datenverarbeitung --
-- Conseils en informatique oriente objet
Ziegelhttenweg 17a, 60598 Frankfurt, Germany, Tl.: +49 (0)69 19 86 27

James Kanze

ulæst,
30. nov. 2001, 12.41.1730.11.2001
til
Sungbom Kim <musi...@bawi.org> wrote in message
news:<3C04FB8E...@bawi.org>...

> I have wondered why std::vector<T>::resize or
> std::vector<T>::operator[] takes unsigned integers as their
> argument, why the Standard made them so. What would you say about
> this? And which would you recommend, signed or unsigned, for such
> functions of a user-defined type I'd write from scratch?

My own pre-standard array types used int, but there was a much more
fundamental reason behind it. I also offered fixed length arrays
(with bounds checking), with the length as as template parameter. The
problem was that if I declared the template:
template< class T , size_t len >
class Array { ... } ;
Then a user who wrote :
Array< int , 20 > a ;
would get an error, because compilers at the time required an exact
type match for the non-type template arguments.

I might add that at that time, I also favored using unsigned for
variables that couldn't be negative. It was a long discussion with
Scott Meyers and Fergus Henderson in comp.lang.c++ (before the
moderated) that changed my mind. And the key point is the silent and
unchecked conversions.

IMHO, having and using an unsigned type for variables that cannot be
negative is a good idea in itself. But C++ is very oriented "int",
and using anything else is generally just fighting the language. And
fighting the language is one battle that you can't win.

--
James Kanze mailto:ka...@gabi-soft.de
Beratung in objektorientierer Datenverarbeitung --
-- Conseils en informatique oriente objet
Ziegelhttenweg 17a, 60598 Frankfurt, Germany, Tl.: +49 (0)69 19 86 27

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

ulæst,
30. nov. 2001, 12.42.5330.11.2001
til
"Mark Wilden" <ma...@mwilden.com> wrote in message
news:<u08ak3i...@news.supernews.com>...

> "James Kanze" <ka...@gabi-soft.de> wrote in message
> news:d6651fb6.01112...@posting.google.com...

> > > I use unsigned integers when it makes no sense for a value to be


> > > negative (this includes most for-loops). This is similar to
> > > using integral types instead of floating types when I'm dealing
> > > with whole numbers--the practice simply represents my intent
> > > more accurately.

> > I agree in theory, and did this for a long time myself. In the
> > end, however, the implicit conversions mean that you've just added
> > another possible error that you can't effectively check for.

> I would just _love_ to have a good reason not to use unsigneds as a
> rule of thumb for counts because of the extra typing and horizontal
> scrolling. :)

> But I don't see what possible error a usage like this could lead to:

> for (unsigned i = 0; i < x; ++i)
> // ...

> To me, using an int here is just wrong, because an int is signed,


> and signedness is semantically meaningless for i. I'd say the same
> about anything that counts.

What's the type of x ? In this case, I would say that that is the
essential issue, because comparison of signed with unsigned can lead
to some surprising results.

If I were designing a new language, I would certainly create both a
signed and an unsigned type. But I would require explicit (and
checked) conversion between them, and add some sort of rules so that a
literal could be used in either context.

C++ doesn't work like this. In practice, C++ is designed to work best
if everything is an int. You can fight the language, but it's a
battle you can't win.

> I think I know what you're saying--that

> unsigned x;
> // ....
> x -= y; // error if y > x

> where x is < y would be a bug I couldn't test for later (though
> there's nothing to prevent me from testing for y > x before the
> subtraction).. Is that correct?

I am actually thinking mainly of the case of function parameters. If
the argument is an expression, it's easy to miss some special case,
and end up with a negative result, even when you didn't want to. If
the function takes an int, it's easy to check for the error. If it
takes an unsigned, it's not.

> > In C/C++, an integral type is int, unless there are imperative
> > reasons to use something else (lack of range, need for modulo
> > overflow handling, etc.).

> This sounds good in theory, but I'd be interested in practical
> reasons why I should change to int in the first loop above, since
> I'd prefer to do so for readability. "C/C++'s integral type is a
> (signed) int" is almost good enough, but if I could add fewer bugs
> to the mix, I'd be sold. :)

I wouldn't really worry about the type in the loop. I normally use
int, because it is the easiest to write. But if there is any STL in
the equation, I'll shift to unsigned, to avoid mixed signed
comparisons.

Where it makes a difference, IMHO, is in the function parameters.
Where the caller doesn't see exactly what you are doing, so it may not
be obvious that a negative value doesn't make sense.

Francis Glassborow

ulæst,
30. nov. 2001, 16.40.0430.11.2001
til
In article <HBeN7.4845$Sa4.6...@news01.chello.no>, Terje Slettebø
<clcppm...@this.is.invalid> writes

>The conversion from unsigned to signed is also such a narrowing conversion,
>only in this case it's only a bit.

That means it is fifty percent of the possible values (yes I know we
often largely use values that fit comfortably in the range but...)

--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Mark Wilden

ulæst,
30. nov. 2001, 16.42.2430.11.2001
til
"James Kanze" <ka...@gabi-soft.de> wrote in message
news:d6651fb6.0111...@posting.google.com...

>
> Where it makes a difference, IMHO, is in the function parameters.
> Where the caller doesn't see exactly what you are doing, so it may not
> be obvious that a negative value doesn't make sense.

I'm beginning to agree that the implicit conversions could cause bugs that
would be impossible to trap:

void foo(unsigned);
foo(-1);

void foo(unsigned u)
{
// u looks fine here!
}

As opposed to

void foo(int);
foo(-1);

void foo(int u)
{
if (i < 0)
throw NegativeArgumentError;
}

Is that what you mean?

Mark Wilden

ulæst,
30. nov. 2001, 16.42.5930.11.2001
til
"Dave Harris" <bran...@cix.co.uk> wrote in message
news:memo.20011130...@brangdon.madasafish.com...

> ma...@mwilden.com (Mark Wilden) wrote (abridged):
>
> However, if we use unsigned only for chicken-counts that are
> always >= 0, then in C++ the type of the difference of two chicken-counts
> will also be unsigned, even though it may be negative.

That's an interesting point.

> In other words, when we declare a type to be unsigned we are saying more
> than "this value will always be >= 0". We are saying something about its
> entire algebra. We are asking for a different kind of mathematics. In
> effect we're asking for modulo-arithmetic instead of normal arithmetic.
> It's about operations, not individual values.

Again, interesting.

> What we want for chickens is a way to say, "This value is an integer which
> is always >= 0." I agree this a reasonable thing to want. C++ does not
> have a good way to say it. C++ only lets us ask for modulo-arithmetic.
> Modulo-arithmetic is not suitable for counting chickens. We shouldn't use
> it for that. We shouldn't declare chicken-counts as unsigned int.

But I'm still not completely convinced, and here's a counter example:

By using ints, we're restricting the algebra to integral operations. We
couldn't find the ratio of one chicken count to another. Does that mean
chicken counts should be doubles?

Pavel Kuznetsov

ulæst,
30. nov. 2001, 17.49.1330.11.2001
til
Terje Slettebø <clcppm...@this.is.invalid> wrote...
> You would, however, usually get a warning from the compiler, if you
> try to assign a signed value to an unsigned variable.

James Kanze <ka...@gabi-soft.de> wrote...
> In which case, you would get so many warnings as to make the compiler
> unusable (at least with these warnings turned on).

I know at least one compiler which gives such a warning and it does
not make the compiler unusable. Instead several errors in legacy
library where found when it was compiled with these warning turned on.
And of course one can suppress these with explicit cast (or even
better one could take advantage of using some kind of checked
numeric_cast<>).

--
Pavel Kuznetsov

[ THE REPLY ADDRESS IS NOT GUARANTEED TO LIVE LONGER THAN FEW WEEKS! ]
[ The permanent address is: pavel <dot> kuznetsov <at> mail <dot> ru ]

Terje Slettebø

ulæst,
30. nov. 2001, 17.55.3930.11.2001
til
"James Kanze" <ka...@gabi-soft.de> wrote in message
news:d6651fb6.0111...@posting.google.com...

> "Mark Wilden" <ma...@mwilden.com> wrote in message
> news:<u08ak3i...@news.supernews.com>...
> > "James Kanze" <ka...@gabi-soft.de> wrote in message
> > news:d6651fb6.01112...@posting.google.com...
>
> > > > I use unsigned integers when it makes no sense for a value to be
> > > > negative (this includes most for-loops). This is similar to
> > > > using integral types instead of floating types when I'm dealing
> > > > with whole numbers--the practice simply represents my intent
> > > > more accurately.
>
> > > I agree in theory, and did this for a long time myself. In the
> > > end, however, the implicit conversions mean that you've just added
> > > another possible error that you can't effectively check for.
>
> If I were designing a new language, I would certainly create both a
> signed and an unsigned type. But I would require explicit (and
> checked) conversion between them, and add some sort of rules so that a
> literal could be used in either context.

I think this is the key issue.

The thing is not that it's wrong, in principle, to use unsigned, for
unsigned values. The thing is that there are all these implicit conversions
(including things like double to char (!)). You also mentioned in another
posting, that key point was the implicit conversions. Do you then agree with
my first line in this paragraph? If so, then we can move on. :)

The whole discussion then boils down to whether the implicit conversions are
balanced with advantages, such as documetation in the code, about the intent
of the type, and possible speed increase, although the issue of intent, I
find more important. Compilers _may_ perform optimizations, which gives the
same results in the code.


> I wouldn't really worry about the type in the loop. I normally use
> int, because it is the easiest to write. But if there is any STL in
> the equation, I'll shift to unsigned, to avoid mixed signed
> comparisons.

Aha. :)

> Where it makes a difference, IMHO, is in the function parameters.
> Where the caller doesn't see exactly what you are doing, so it may not
> be obvious that a negative value doesn't make sense.

>From this, I finf it a little hard to understand why you had such a
confrontational line in the posting about efficiency. But then, maybe you
think the efficiency is a minor issue, and it's easily outweighted by other
issues. I don't disagree with that. It doesn't invalidate my observation
that in the given code, different code was generated.

Therefore, like in the example given here, where the unsigned variable isn't
usen in any operation that can yield a negative value, and where it may
actually be an advantage, for compatibility with e.g. size_type, it may be
an advantage to use unsigned.


Regards,

Terje Slettebo

John Scott

ulæst,
30. nov. 2001, 17.57.0330.11.2001
til
> I find unsigned numbers very useful, actually. I tend to use it to put
> semantics into my program (similar to using const), that is enforced by
the
> program. It's simple: When you use an unsigned number, you _know_ it can't
> be negative (thus, you _can_ ensure positiveness).

I don't think this ensures positiveness because convertion from signed to
unsigned can occur silently.

>
> Since it can't be negative, you may also avoid checks for negativeness,
like
> this:
>
> void f(int i) // Signed
> {
> if(i>=0 && i<10)
> ...
> }
>
> void f(unsigned int i) // Unsigned
> {
> if(i<10)
> ...
> }
>

int x = -1; f(x); doesn't cause any compiler warnings and is treated as if i
>0 in f(). Surely this is no good...

John Lakos (Large Scale C++ Software Design) suggests considering the
following:

1. Using unsigned does not ensure at compile time that negative numbers will
not be passed at runtime. The C++ language allows bit patterns to be
reinterpreted silently at runtime (i.e. f(-1) does not give an error). Sure
you get warnings for "strlen(myStr) < myInt", but not for int x = -1; f(x);

2. Using unsigned does not allow for the negative value checking without
first converting back to signed.

3. Using unsigned only increases the size of an integer by 1 bit. There is a
risk of losing this extra value when it is converted back to a signed. Even
an unsigned int converted to a signed long can lose data because int & long
are the same size on many platforms.

4. Lakos considers that using unsigned increases the chance of error and I
tend to agree. Without looking at the header file there is no safety
advantage (because conversions are done silently at runtime). Using an
unsigned return value in an expression involving a negative int will cause
the expression to evaluate incorrectly because the int is converted to an
unsigned and becomes a very large positive value.

5. Using an unsigned interferes with function overloading. If another
function called f(double) was created with the f(unsigned) above, the
compiler cannot determine which to use for the statement int x = -1; f(x);
because the convertion from int to unsigned and int to double are both
standard conversions.

6. Using unsigned can interfere with template instantiation because the
argument must match exactly. Thus template<unsigned N> requires an unsigned.
Thus if we had template<unsigned N> class Bits { int _bits:N... then Bits<2>
would not work because we got an int, not an unsigned. Thus we would have to
do Bits<unsigned(2)> or some such.

Since reading Large Scale C++ Software Design, I have changed my views on
unsigned. I used to think they were a good idea. Now I don't. Since I've
stopped using them I find my code easier to read and to debug.

Regards
John.

Dave Harris

ulæst,
30. nov. 2001, 19.25.2630.11.2001
til
ma...@mwilden.com (Mark Wilden) wrote (abridged):
> By using ints, we're restricting the algebra to integral operations. We
> couldn't find the ratio of one chicken count to another. Does that mean
> chicken counts should be doubles?

Good riposte :-)

I think division is different to addition or subtraction. If we add or
subtract chickens we get some number of chickens - the units don't change.
Division of chickens yields a pure number, not a chicken-count. Its units
are different so it is not a big surprise to find its type is different
too.

There are also pragmatic issues. Using doubles instead of ints would cause
even more changes to the arithmetic. For example, doubles don't support
operator++(); they can't index arrays or be switch labels or template
parameters. Their runtime costs are much higher. That alone would prevent
many people from using doubles.

In some ways doubles are as bad as unsigned, because they are as
contagious. Adding a signed to an unsigned yields an unsigned. Adding an
int to a double yields a double. If we replace an int with almost any
other type we will either need casts to turn it back into an int, or else
have the new type propagate through the system. Propagating the type is a
non-local change which shouldn't be done for the sake of a local ad hoc
convenience such a more expressive for-loop counter.

Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
bran...@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed

http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."

Terje Slettebø

ulæst,
30. nov. 2001, 19.25.4430.11.2001
til
"Mark Wilden" <ma...@mwilden.com> wrote in message
news:u0fklq4...@news.supernews.com...

> "Dave Harris" <bran...@cix.co.uk> wrote in message
> news:memo.20011130...@brangdon.madasafish.com...
> > ma...@mwilden.com (Mark Wilden) wrote (abridged):
> >
> > However, if we use unsigned only for chicken-counts that are
> > always >= 0, then in C++ the type of the difference of two
chicken-counts
> > will also be unsigned, even though it may be negative.
>
> But I'm still not completely convinced, and here's a counter example:
>
> By using ints, we're restricting the algebra to integral operations. We
> couldn't find the ratio of one chicken count to another. Does that mean
> chicken counts should be doubles?

Good point. :)

This shows a general application of the principle here about applying
operations on types where they make no sense.

The same goes if you apply operations on unsigned numbers, if the operation
makes no sense.


Regards,

Terje Slettebo

Francis Glassborow

ulæst,
30. nov. 2001, 19.26.0230.11.2001
til
In article <9u8rbq$dml$1...@plutonium.btinternet.com>, John Scott
<john-...@bigfoot.nospam> writes

>Since reading Large Scale C++ Software Design, I have changed my views on
>unsigned. I used to think they were a good idea. Now I don't. Since I've
>stopped using them I find my code easier to read and to debug.

Unfortunately there are many places where the Standard Library uses
size_t so we really need compilers to warn about those silent
conversions.


--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Terje Slettebø

ulæst,
1. dec. 2001, 04.33.5201.12.2001
til
"James Kanze" <ka...@gabi-soft.de> wrote in message
news:d6651fb6.01112...@posting.google.com...
> Terje Sletteb <clcppm...@this.is.invalid> wrote in message
> news:<sZXM7.4733$Sa4.6...@news01.chello.no>...
>
> [...]
> > > Have you actually measured the difference in a real program, with
> > > a modern compiler? And found it to be a bottleneck in your code?
>
> > No.
>
> > But I did give concrete assembler-listings in a posting in this
> > thread, showing the difference.
>
> But did it result in a measurable difference in the execution time of
> a real program. If not, who cares?

Like I said in the message, the reason for testing this, and providing the
assembler listings, was to test the following claim you came with:

>Compilers generally know what the machine instructions do. The
>compile I worked on (almost 15 years ago) had no trouble optimizing
>the comparison with signed, and generated exactly the same code in
>both cases.

I demonstrated that, at least for the two I tested it on, this did not hold.

What you asked the question regarding bottleneck to, was my quote below
here:

> However, again, if you know the values are positive, it's safe to
> use unsigned types, and, like in the example with if(), above, it
> actually makes it more efficient.

There doesn't need to be a bottleneck, in order to do something that's
faster. There has been said things about premature optimizations. However, I
think one should do things right, from the start. Meaning that if you know
one way is faster than another, it makes sense to use the faster way, if
there are no other concerns, or if, when balancing it, the advantage of the
speed outweights other concerns.

To take an extreme example, I assume you wouldn't use the following to set a
variable to a value:

int i;

for(i=0;i<10;i++);

Rather than:

i=9;

This is regardless of whether or not this had any perfomance impact on the
code. The first version unnecessarily burn cycles, for no benefit. It would
be just stupid to use it. Do you see my point, here?

If using unsigned have no disadvantages, otherwise, then even a small
efficiency-increase (especially if it's code that's executed a lot, in a
speed-critical part of the code) would be useful.

Your question about if it's a bottleneck, and if not, who cares, has the
underlying assumption that there are disadvantages with using unsigned. Do
you agree with me that there is this assumption?

Given this, whether or not to use unsigned, it then becomes to balance any
possible advantage with using it, with any possible disadvantage of using
it.

Your answer about who cares, shows that, unless there's a large
speed-difference, you don't think it balances in the way of advantages.
Others may have a different evaluation of this. There are things you get
with unsigned, such as possible speed-increase, and a documentation in the
code that the variable is always positive. Then, there's also things like
implicit conversion from signed to unsigned, which may give the wrong
answer.

Such conversions from signed to unsigned, isn't the only implicit
conversions that may give a wrong value, though. Others include narrowing
conversions.

It's not as clear cut as you may try to give the impression of, here.

Given the above, I don't think I need to demonstrate a big speed-increase,
as that relies on the assumption that using unsigned has big disadvantages.
Which I don't think is the case.


> > But how can you check for integer overflow, in C++?
>
> In in advance, by verifying that the operands are in a range that
> won't cause overflow. A C++ compiler *could* generate code to check;
> in the 80x86 architecture, there is (or at least was) an instruction
> especially designed for this, INTO, which would trigger a software
> interrupt if the overflow bit was set.

My question was regarding your following quote:

> Actually, there's a real reason to use unsigned hidden in this
> statement. Overflow is a defined operation in unsigned arithmetic

My question was, can you take advantage of this defined behaviour? In other
words, does code with int and unsigned int behave differently, in this
respect?

Since there's no way, in C++, to catch integer overflow (except by checking
the numbers before), I guess this defined behaviviour can only be used, in
that the high-order bits simply gets discarded.


>IMHO, on decent hardware, this
> would be the normal case, and you'd have to take special steps to
> avoid it

What do you mean here? That (signed or unsigned) integer overflow triggers a
hardware exception? For that to happen, the compiler would have to include
checks for this after each arithmetc operation, which would be extremely
wasteful, and could easily double the size of the code.

Therefore, this isn't done. What do you then mean with that you have to take
special steps to avoid it?


Regards,

Terje Slettebo

Terje Slettebø

ulæst,
1. dec. 2001, 04.34.1001.12.2001
til
"James Kanze" <ka...@gabi-soft.de> wrote in message
news:d6651fb6.01112...@posting.google.com...
> Sungbom Kim <musi...@bawi.org> wrote in message
> news:<3C04FB8E...@bawi.org>...
>
> > I have wondered why std::vector<T>::resize or
> > std::vector<T>::operator[] takes unsigned integers as their
> > argument, why the Standard made them so. What would you say about
> > this? And which would you recommend, signed or unsigned, for such
> > functions of a user-defined type I'd write from scratch?
>
> My own pre-standard array types used int, but there was a much more
> fundamental reason behind it. I also offered fixed length arrays
> (with bounds checking), with the length as as template parameter. The
> problem was that if I declared the template:
> template< class T , size_t len >
> class Array { ... } ;
> Then a user who wrote :
> Array< int , 20 > a ;
> would get an error, because compilers at the time required an exact
> type match for the non-type template arguments.
>
> I might add that at that time, I also favored using unsigned for
> variables that couldn't be negative. It was a long discussion with
> Scott Meyers and Fergus Henderson in comp.lang.c++ (before the
> moderated) that changed my mind. And the key point is the silent and
> unchecked conversions.

Wasn't it also Scott Meyers who wrote the following in an email:

using namespace std; // so sue me

which started a long discussion here, a while ago?

From what I understand, also in this case, there was a discussion about what
would be an advantage.


Regards,

Terje Slettebo

Terje Slettebø

ulæst,
1. dec. 2001, 04.35.2001.12.2001
til
"Francis Glassborow" <francis.g...@ntlworld.com> wrote in message
news:qIEAXtBU...@robinton.ntlworld.com...

> In article <HBeN7.4845$Sa4.6...@news01.chello.no>, Terje Slettebø
> <clcppm...@this.is.invalid> writes
> >The conversion from unsigned to signed is also such a narrowing
conversion,
> >only in this case it's only a bit.
>
> That means it is fifty percent of the possible values

Yes, I know this.

However, consider another implicit conversion such as int to char, where (if
the int is 32-bit) 3/4 of the bits, or almost 100% of the possible values,
are lost.

It was to compare it to such conversions, that I said it's only a bit.

The point is that any such implicit conversion could give a wrong value, if
the value can't be represented in the variable.

I guess the implicit conversions between the built-in types is much a legacy
from C. Conversion between user-defined types in C++, has no such implicit
conversion (not even using the constructor, if you use "explicit").


Regards,

Terje Slettebø

Terje Slettebø

ulæst,
1. dec. 2001, 04.36.3101.12.2001
til
"John Scott" <john-...@bigfoot.nospam> wrote in message
news:9u8rbq$dml$1...@plutonium.btinternet.com...

> > I find unsigned numbers very useful, actually. I tend to use it to put
> > semantics into my program (similar to using const), that is enforced by
> the
> > program. It's simple: When you use an unsigned number, you _know_ it
can't
> > be negative (thus, you _can_ ensure positiveness).
>
> I don't think this ensures positiveness because convertion from signed to
> unsigned can occur silently.

Yes, I know. I've mentioned that in other postings, since that, too.

My point was that if you have an unsigned variable, you _know_ that it's
positive (because it can't be negative).

There is, however, as you mention, an implicit conversion from signed to
unsigned (as well as between other types), which can result in a wrong
value.


> int x = -1; f(x); doesn't cause any compiler warnings and is treated as if
i
> >0 in f(). Surely this is no good...

Neither does this:

void f(int n)
{
cout << n; // This will not print "1e20"...
}

int main()
{
double n=1e20;

f(n); // Opps, narrowing conversion, the large number disappeared. No
warning here.
}


However, noone has argued that "int" should not be used as parameter for
functions, because of this. Do you?

In that case, what _should_ one use? Even double is not guaranteed to hold
an int, without loss of precision.

It's a general theme of using values or operations that makes no sense for
the given type. This isn't particular for unsigned.


> int x = -1; f(x); doesn't cause any compiler warnings and is treated as if
i
> >0 in f(). Surely this is no good...

It's just as good as using other types, as I've shown above. If the values
are known to be positive, unsigned may be better. On the other hand, there's
also the implicit conversions.

Points 1, 2 and 3 regards the implicit conversions, and that is also the
case for the other built-in types.

Point 4 regards the use of unsigned types together with signed types. Again,
like in my example above, using an implicit conversion from double to int,
such operations involving other types, may give the wrong answer.

Point 5 again deals with conversion from signed to unsigned. Nothing new
there. The point is that if you're calling a function taking an unsigned
int, with a negative number, then it's actually an advantage that the
compiler treats this as a conversion, and flags it as ambiguous, relative to
f(double). In this case, the compiler actually stops it, something it
wouldn't do, if f(int) was used, yet the value passed to f() shouldn't be
negative.

Thus, in this case, using unsigned gives a warning, when using an invalid
value for the function, something int wouldn't do.

Point 6 regards that constants are considered signed.

I actually tested this, because I was curious if this was the case. I did
this (using the Intel C++ compiler):

template<unsigned int n>
class Test
{
};

Test<1> test; // No error given

const int i=1;

Test<i> test; // No error here, either

Test<-1> test; // Warning, integer conversion resulted in a change of sign


As you can see, the compiler knows the number used to instantiate the
template, and it performs a conversion to do this. Thus, Point 6 does not
hold.

Actually, as can be seen from the last example, having the template
parameter as unsigned, is actually enforced by the compiler (at least this
one). This would not be the case if signed was used.

Thus, this is actually an argument for unsigned, not against it. Because
here, it's able to check the conversion.


After having answered these things again and again, I think it boils down to
this:

The point is that with unsigned variables, like the rest of C++, brain is
not optional. It is required. :)

Using unsigned variables makes it clear in the code that the variable can't
be negative. It adds the intent to the code. As someone else mentioned, it's
a compilable documentation.

However, because of implicit conversions, conversion from signed may give
the wrong value. However, this also pertains to the other implicit
conversions between the built-in types.


I think James Kanze said it well in another posting:

>If I were designing a new language, I would certainly create both a
>signed and an unsigned type. But I would require explicit (and
>checked) conversion between them, and add some sort of rules so that a
>literal could be used in either context.

I think this is the essence of it.

Making run-time checks for such conversions may be costly, though. But at
least a cast, like a numeric_cast<int>((nsigned int value)) would make it
clear that you mean it, so that no implicit, possibly wrong conversions, are
used.

This would bring it in line with the strict type-checking of user-defined
types (and could also stop other implicit conversions, such as from double
to char).


Regards,

Terje Slettebo

Mark Wilden

ulæst,
1. dec. 2001, 04.37.0701.12.2001
til
"Dave Harris" <bran...@cix.co.uk> wrote in message
news:memo.20011130...@brangdon.madasafish.com...
>
> I think division is different to addition or subtraction. If we add or
> subtract chickens we get some number of chickens - the units don't change.
> Division of chickens yields a pure number, not a chicken-count. Its units
> are different so it is not a big surprise to find its type is different
> too.

I'll buy that. And in fact this discussion has changed my mind (again) about
using unsigned. I'm going to use ints again, even for counts. And I'll save
some typing. :)

Terje Slettebø

ulæst,
1. dec. 2001, 04.37.2801.12.2001
til
"Dave Harris" <bran...@cix.co.uk> wrote in message
news:memo.20011130...@brangdon.madasafish.com...
> ma...@mwilden.com (Mark Wilden) wrote (abridged):
> > By using ints, we're restricting the algebra to integral operations. We
> > couldn't find the ratio of one chicken count to another. Does that mean
> > chicken counts should be doubles?
>
> There are also pragmatic issues. Using doubles instead of ints would cause
> even more changes to the arithmetic. For example, doubles don't support
> operator++();

Actually, they do.

Or is this non-standard?

> they can't index arrays

If they are implicitely converted to int, they can. But I agree, a
conversion is needed.


Regards,

Terje Slettebo

Dave Harris

ulæst,
1. dec. 2001, 15.03.5901.12.2001
til
tsle...@acm.org (=?Windows-1252?Q?Terje_Sletteb=F8?=) wrote (abridged):

> > even more changes to the arithmetic. For example, doubles don't
> > support operator++();
>
> Actually, they do.

I think you're right; sorry. For a large enough double, operator++() will
leave it unchanged so it is a bit unintuitive, but as far as I can tell it
is still supported.


> > they can't index arrays
>
> If they are implicitely converted to int, they can. But I agree, a
> conversion is needed.

And it's a lossy conversion. Good compilers will issue a warning about
loss of precision. That makes it impractical to use, in my view. I prefer
code to compile without warnings.

Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
bran...@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Francis Glassborow

ulæst,
1. dec. 2001, 16.32.0701.12.2001
til
In article <J0SN7.5419$Sa4.6...@news01.chello.no>, Terje Slettebų
<tsle...@acm.org> writes

>There doesn't need to be a bottleneck, in order to do something that's
>faster. There has been said things about premature optimizations. However, I
>think one should do things right, from the start. Meaning that if you know
>one way is faster than another, it makes sense to use the faster way, if
>there are no other concerns, or if, when balancing it, the advantage of the
>speed outweights other concerns.


Let me rephrase that. 'If you know that one way is essentially faster
than another...' Any time you start looking at assembler code you
clearly do not know that. All you see are the results for one particular
setting of the switches on a specific release of a single compiler.
Using that kind of information without absolute need is most certainly
premature optimisation. It makes your code vulnerable to change. Worse,
if the piece of code you are 'optimising' results in saving a handful of
cycles per execution of the program it is likely that the total savings
for all the runs ever made by your program will be less than the time
you took to make that 'optimisation.'

One cause of missed deadlines is programmers who try to write
(unnecessarily) fast code. Often such code is also hard to debug and
then maintain because it is not straightforward.


--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Terje Slettebø

ulæst,
1. dec. 2001, 18.08.4001.12.2001
til
"Francis Glassborow" <francis.g...@ntlworld.com> wrote in message
news:I+mo6RBQ...@robinton.ntlworld.com...
> In article <J0SN7.5419$Sa4.6...@news01.chello.no>, Terje Slettebø

> <tsle...@acm.org> writes
> >There doesn't need to be a bottleneck, in order to do something that's
> >faster. There has been said things about premature optimizations.
However, I
> >think one should do things right, from the start. Meaning that if you
know
> >one way is faster than another, it makes sense to use the faster way, if
> >there are no other concerns, or if, when balancing it, the advantage of
the
> >speed outweights other concerns.
>
>
> One cause of missed deadlines is programmers who try to write
> (unnecessarily) fast code. Often such code is also hard to debug and
> then maintain because it is not straightforward.

By the way, I know this, too.

I prefer to write code that is self-documenting.

I'm quite a fan of Extreme Programing.

If you again look at my quote above, here, you'll see I wasn't talking about
optimizing, or doing something that would make the code harder to
understand. I was talking about do it right, from the start.

Also note that I said _if there are no other concerns_. Such conserns
include readability.

Therefore, your rephrase:

"> Let me rephrase that. 'If you know that one way is essentially faster
> than another...'

only includes the first part.


Regards,

Terje Slettebo

John Potter

ulæst,
1. dec. 2001, 18.09.1801.12.2001
til
On 1 Dec 2001 04:37:07 -0500, "Mark Wilden" <ma...@mwilden.com> wrote:

> "Dave Harris" <bran...@cix.co.uk> wrote in message
> news:memo.20011130...@brangdon.madasafish.com...
> >
> > I think division is different to addition or subtraction. If we add or
> > subtract chickens we get some number of chickens - the units don't change.
> > Division of chickens yields a pure number, not a chicken-count. Its units
> > are different so it is not a big surprise to find its type is different
> > too.
>
> I'll buy that. And in fact this discussion has changed my mind (again) about
> using unsigned. I'm going to use ints again, even for counts. And I'll save
> some typing. :)

You will never again write a "correct" loop for vectors?

for (vector<double>::size_type x = 0; x != v.size(); ++ x)
v[x] *= v[x];

John

Terje Slettebø

ulæst,
1. dec. 2001, 18.10.4601.12.2001
til
"Francis Glassborow" <francis.g...@ntlworld.com> wrote in message
news:I+mo6RBQ...@robinton.ntlworld.com...
> In article <J0SN7.5419$Sa4.6...@news01.chello.no>, Terje Slettebø

> <tsle...@acm.org> writes
> >There doesn't need to be a bottleneck, in order to do something that's
> >faster. There has been said things about premature optimizations.
However, I
> >think one should do things right, from the start. Meaning that if you
know
> >one way is faster than another, it makes sense to use the faster way, if
> >there are no other concerns, or if, when balancing it, the advantage of
the
> >speed outweights other concerns.
>
> Let me rephrase that. 'If you know that one way is essentially faster
> than another...' Any time you start looking at assembler code you
> clearly do not know that. All you see are the results for one particular
> setting of the switches on a specific release of a single compiler.
> Using that kind of information without absolute need is most certainly
> premature optimisation.

Francis, I was talking about this, on general grounds.

I tried to explain it, calmly, in that message.

I did _not_ specifically talk about unsigned.

I talked about, in general if you know some way is better. I did not say
using assembler code to know it. In the case of unsigned, I demonstrated
with some assembler.


> It makes your code vulnerable to change. Worse,
> if the piece of code you are 'optimising' results in saving a handful of
> cycles per execution of the program it is likely that the total savings
> for all the runs ever made by your program will be less than the time
> you took to make that 'optimisation.'

Again, I was not talking about optimizations. I was talking about making it
right, from the start. I even gave a code-example, to explain what I meant,
in that message, and even then it was misunderstood, now!

One would almost think I've put out some flame-bait, given these reactions.

Look, people. I haven't even said that the assembler output justifies using
unsigned. As it's pointed out, that may well produce identical results for
signed and unsigned, on another compiler.

Therefore, it's been more about that with unsigned, one expresses, in the
code, that something is positive. On the other hand, there's the implicit
conversions from signed, and the effect of using unsigned in operations that
could yield a negative number.


> One cause of missed deadlines is programmers who try to write
> (unnecessarily) fast code. Often such code is also hard to debug and
> then maintain because it is not straightforward.

This was a general discussion about using unsigned.

In this discussion, I brought up, in the last posting, the general thing,
that if you know some way is better, it makes sense to do it from the start.
I don't think you will disagree with that?

If you don't disagree with that, then there's no disagreement on that issue.

That was a general issue, separate from unsigned.


Regards,

Terje Slettebo

Terje Slettebø

ulæst,
2. dec. 2001, 01.31.1602.12.2001
til
"Francis Glassborow" <francis.g...@ntlworld.com> wrote in message
news:I+mo6RBQ...@robinton.ntlworld.com...
> In article <J0SN7.5419$Sa4.6...@news01.chello.no>, Terje Slettebø

> <tsle...@acm.org> writes
> >There doesn't need to be a bottleneck, in order to do something that's
> >faster. There has been said things about premature optimizations.
However, I
> >think one should do things right, from the start. Meaning that if you
know
> >one way is faster than another, it makes sense to use the faster way, if
> >there are no other concerns, or if, when balancing it, the advantage of
the
> >speed outweights other concerns.

Unfortunately, it's not possible to recall a message, to add something to
it, so here's another addition, to the two other messages (replies to your
message). :)


Therefore, I prefer to express my _intent_ in the code, and let the compiler
handle the low-level details.

This ensures that the compiler gets the maximum amount of clues, and can
therefore make the most efficient code.

As you can see, I completely agree with this.

One thing, as Bjarne Stroustrup has pointed out, is that with C++, you can
have both elegance and efficiency.

That's really what I've tried to express, here.

This also ensures that the code is easier to understand, maintain and
extend. And that it performs well on other platforms, where, if one instead
used a particular low-level hack on one platform, it might be completely
unnecessary, or even degrade performance, on another platform.

This is also an argument for letting the compiler handle the inlining, since
it has the full context, and knows what code is generated.

One of those clues one could give, is that this particular variable is
always positive.

However, there's also the issue of implicit conversions between signed and
unsigned.


Regards,

Terje Slettebo

Michael Sullivan

ulæst,
3. dec. 2001, 00.42.2003.12.2001
til
Terje Slettebo wrote:
> "Francis Glassborow" <francis.g...@ntlworld.com> wrote in message
> news:m7JzLmAg...@robinton.ntlworld.com...

> On another message to you in this thread, I mentioned that at least on Intel
> C++, this is handled by only giving a warning in the case of a conversion
> _changing the sign_, when converting from signed to unsigned.

Oh no, it doesn't. Providing *that* warning at compile time for all
programs is equivalent to the halting problem.

It might be able to make intelligent guesses, but at compile time, it
can only know for certain whether a sign switch will occur for const
values.

Compilers != oracles


Michael

Sungbom Kim

ulæst,
3. dec. 2001, 00.45.4103.12.2001
til
Dave Harris wrote:
>
> Size_t is often an unsigned type because it needs to be at least big
> enough to measure physical memory. Physical memory often comes in sizes
> like 64k, or 4Gb, and a signed type would either be too small or extremely
> wasteful.

Isn't size_t not just often unsigned but required to be unsigned?

I don't have the standard, but Stroustrup says in TC++PL 6.2.1:

"The result of sizeof is of an unsigned integral type called size_t
defined in <cstddef>. The result of pointer subtraction is of a
signed integral type called ptrdiff_t defined in <cstddef>."

> That said, vector's use of unsigned types can cause problems. Eg:
>
> [example "int count" snipped]
>
> will fail to compile because std::min() likes both its arguments to have
> the same type, and vector didn't use int.
>
> One way to fix it is to change "int count" to "size_t count". In this way
> an unsigned type can propagate through a program. They are infectious, a
> bit like const-correctness. I see this as another reason not to use
> unsigned casually.

Yes, I bitterly agree about the propagation of unsignedness!

--
Sungbom Kim <musi...@bawi.org>

Gerhard Menzl

ulæst,
3. dec. 2001, 06.13.5603.12.2001
til
Mark Wilden wrote:

> > You must be a real job hopper then. :-)
>
> You know, I hear these kinds of horror stories, and, while I don't think
> I've been gifted with especially intelligent C++ coworkers, I thank my
> lucky stars that they haven't been as bad as that! :)

On further reflection, I found you don't have to be exceptionally dumb
to run into the unsigned decrement trap we were talking about. A little
inexperience or hastiness can do the job as well. Suppose the original
author of the loop (let's call him M.) decided to use unsigned int for
counting because, he reasoned, you can't have a negative number of geese
after all. Being a fan of self-documenting code, he also decided to use
a typedef:

// PopularDefinitions.h

typedef unsigned int Counter;

The loop originally looked like this:

// MyClass.cpp

#include <PopularDefinitions.h>
#include "MyClass.h"

//...

void MyClass::f ()
{
for (Counter c = myTotal; c > 0; --c)
{
// do whatever justifies descending order

myArray[c - 1] = doWhateverJustifiesDescendingOrder ();
}
}

Six months later, M.'s colleague G. takes over. He's fresh from college,
and his first task is to build in a feature that requires several
operations on each array element inside the loop. Finding he has to
type:

myArray[c - 1]

three times in a row, he is worried about recomputing the array index
every time, so he changes the loop to:

for (Counter c = myTotal - 1; c >= 0; --c)
{
// ...
}

Surely Counter is a signed type. He's seen it somewhere the day before,
the day before this terrible hangover.

Bang!

Of course, in a perfect world, G. would have looked up the definition of
Counter. He would have factored out the operations into a separate
function. He wouldn't drink too much and indulge in premature
optimization the next day. There would be code reviews. In fact, the
whole issue wouldn't have arisen at all because std::vector and
std::vector::reverse_iterator would have been used right from the
beginning.

But the world isn't perfect, and stupid programming errors happen
without necessarily involving total morons.

It's better to have more than one line of defence.

Gerhard Menzl

Sungbom Kim

ulæst,
3. dec. 2001, 06.14.3603.12.2001
til
Dave Harris wrote:
>
> In other words, when we declare a type to be unsigned we are saying more
> than "this value will always be >= 0". We are saying something about its
> entire algebra. We are asking for a different kind of mathematics. In
> effect we're asking for modulo-arithmetic instead of normal arithmetic.
> It's about operations, not individual values.

This reminds me of the fact that a type is defined by both the set of
possible values of that type and the set of possible operations that
may be performed on them, which I've been failing to recognise.
Thanks for the good point.

> What we want for chickens is a way to say, "This value is an integer which
> is always >= 0." I agree this a reasonable thing to want. C++ does not
> have a good way to say it. C++ only lets us ask for modulo-arithmetic.
> Modulo-arithmetic is not suitable for counting chickens. We shouldn't use
> it for that. We shouldn't declare chicken-counts as unsigned int.

Now I realise that operations ('algebra' that you mentioned, in case
of numeric types) should be considered as a fundamental criterion
when I choose types.

--
Sungbom Kim <musi...@bawi.org>

Dylan Nicholson

ulæst,
3. dec. 2001, 12.41.4803.12.2001
til
ka...@gabi-soft.de (James Kanze) wrote in message
news:<d6651fb6.01112...@posting.google.com>...
>
> > To take the example of char. Signed char gives the range -128 to
> > 127. Unsigned char gives 0 to 255. Not useful? I'd definitely think
> > it's useful. You just got twice as large positive range. The same
> > goes for all the integers.
>
> The problem is: if 128 is not sufficient today, then 256 will not be
> sufficient tomorrow. If 128 isn't sufficient, then use short.
>
And what if you're dealing with numbers that need to be as large as
possible, where you're prepared to accept a compiler-enforced limit of
2^32, but 2^31 is obviously too restrictive. This has occurred more
than once before in my experience, and has been the justification for
using unsigned as opposed to signed. Obviously once 64-bit types are
widely available on all common platforms, it will be (I suspect) a
little while before the difference between 2^63 and 2^64 becomes an
issue, but for the time being there is a real problem,
especially when these restrictions are passed on to users (as they
often are - for instance, our software can only support finite-element
meshes of a certain size - for nearly all of our users the limit is
quite acceptable. If we were to use signed types for indexing 2D
matrices, that limit would probably be reduced by four-fold, we would
upset most of our customers!)

Dylan

Mark Wilden

ulæst,
3. dec. 2001, 16.02.3203.12.2001
til
"Gerhard Menzl" <gerhar...@sea.ericsson.se> wrote in message
news:3C0B45A8...@sea.ericsson.se...
>
> typedef unsigned int Counter;

>
> for (Counter c = myTotal; c > 0; --c)

This is wrong, in my opinion. The typedef is being incorrectly used. An
index is not a counter.

> Surely Counter is a signed type. He's seen it somewhere the day before,
> the day before this terrible hangover.

How could a Counter be signed??

> Of course, in a perfect world, G. would have looked up the definition of
> Counter. He would have factored out the operations into a separate
> function. He wouldn't drink too much and indulge in premature
> optimization the next day. There would be code reviews. In fact, the
> whole issue wouldn't have arisen at all because std::vector and
> std::vector::reverse_iterator would have been used right from the
> beginning.

You don't include unit testing in that list. Whenever I hear about supposed
dangers from these idiot maintenance programmers, I have to wonder why their
company's testing procedure is so flawed that obvious bugs like this aren't
caught immediately. We're talking about an infinite loop under all
circumstances. How hard is that to test for?

Francis Glassborow

ulæst,
3. dec. 2001, 16.22.5703.12.2001
til
In article <156b8737.01120...@posting.google.com>, Dylan
Nicholson <dy...@moldflow.com> writes

>And what if you're dealing with numbers that need to be as large as
>possible, where you're prepared to accept a compiler-enforced limit of
>2^32, but 2^31 is obviously too restrictive. This has occurred more
>than once before in my experience, and has been the justification for
>using unsigned as opposed to signed.

Accepting this argument implies that all implicit conversions from
signed to unsigned will be detected because given your premise, small
negative (in twos complement) values will convert to legal but erroneous
large unsigned values.


--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Mark Wilden

ulæst,
4. dec. 2001, 06.16.2004.12.2001
til
"John Potter" <jpo...@falcon.lhup.edu> wrote in message
news:3c09579e...@news.uplink.net...

>
> You will never again write a "correct" loop for vectors?
>
> for (vector<double>::size_type x = 0; x != v.size(); ++ x)
> v[x] *= v[x];

I've never written it before, so no, I don't expect to write it again.

for (vector<double>::iterator it = v.begin(); it != v.end(); ++it)
*it *= *it;

Daryle Walker

ulæst,
4. dec. 2001, 06.24.3304.12.2001
til
Francis Glassborow <francis.g...@ntlworld.com> wrote:

> In article <3C01148D...@worldnet.att.net>, James Rogers
> <jimmaure...@worldnet.att.net> writes
> >The result would be a type with a range of 0 through 11. There would
> >still be some mapping ineffiencies with the desired range of 1
> >through 12. Such a type, however, might have the modular nature
> >of its math pre-defined. This would be a useful feature. Note that
> >the modular integer type would map efficiently to array indices.
>
> Indeed modular integers are so pervasive in the real world that I think
> they make a good candidate for being a Standard template class:
>
> template<unsigned int upper_bound>
> class modular {
> ...
> };
>
> And implementing that should use the hoisting idiom to stop code bloat.

What's the hoisting idiom? (I'm have an interim modulo class for Boost
and I'm wondering if your idea is feasible.)

--
Daryle Walker
Mac, Internet, and Video Game Junkie
dwalker07 AT snet DOT net

Dylan Nicholson

ulæst,
4. dec. 2001, 06.27.0304.12.2001
til
Francis Glassborow <francis.g...@ntlworld.com> wrote in message news:<T4SO7UHD...@robinton.ntlworld.com>...

> In article <156b8737.01120...@posting.google.com>, Dylan
> Nicholson <dy...@moldflow.com> writes
> >And what if you're dealing with numbers that need to be as large as
> >possible, where you're prepared to accept a compiler-enforced limit of
> >2^32, but 2^31 is obviously too restrictive. This has occurred more
> >than once before in my experience, and has been the justification for
> >using unsigned as opposed to signed.
>
> Accepting this argument implies that all implicit conversions from
> signed to unsigned will be detected because given your premise, small
> negative (in twos complement) values will convert to legal but erroneous
> large unsigned values.

I think I can state that with some confidence. We're only using
unsigned values for array sizes and indices. So as long as whatever
is creating the initial data doesn't let the count grow over UINT_MAX
(easy enough to do), then code manipulating the resulting data isn't
going to have a problem.

Dylan

Gerhard Menzl

ulæst,
4. dec. 2001, 06.35.0504.12.2001
til
Mark Wilden wrote:

> >
> > typedef unsigned int Counter;
> >
> > for (Counter c = myTotal; c > 0; --c)
>
> This is wrong, in my opinion. The typedef is being incorrectly used. An
> index is not a counter.
>
> > Surely Counter is a signed type. He's seen it somewhere the day before,
> > the day before this terrible hangover.
>
> How could a Counter be signed??

Sigh. You're beginning to split hairs. When iterating through an array
in a for loop, you typically use the variable that controls the loop
both as a counter and as an index. You may call your typedef whatever
you want (Index, CounterIndex, IndexCounter, Iterator); the problem
remains the same. Others might argue that an index cannot be negative.
It is really a matter of what different people find intuitive. I
wouldn't be surprised if there are folks out there who find the concept
of -3 chickens perfectly natural. <g>

> You don't include unit testing in that list. Whenever I hear about
> supposed dangers from these idiot maintenance programmers, I have to
> wonder why their company's testing procedure is so flawed that obvious
> bugs like this aren't caught immediately. We're talking about an infinite
> loop under all circumstances. How hard is that to test for?

The list was not exhaustive, and the example was contrived. With a
little mental flexibility, you can easily imagine a case that is not
that obvious.

Gerhard Menzl

Francis Glassborow

ulæst,
4. dec. 2001, 18.47.0104.12.2001
til
In article <1f3uv35.ec4g2f1t8cxbiN%dwal...@snet.net.invalid>, Daryle
Walker <dwal...@snet.net.invalid> writes

>What's the hoisting idiom? (I'm have an interim modulo class for Boost
>and I'm wondering if your idea is feasible.)

The hoisting idiom refers to a process of encapsulating common
functionality in a base class. For example implementations of
specialisations of containers for pointers might use full specialisation
of the container for void*. So we get something like (simplified,
because this is just to provide the idea)

template <typename T>
class container {
// ...
};

template <>
class container<void *> {
// ...
};

template <typename T>
class container<T*> : container<void*> {
// and much of the implementation delegates
// to the private base class
};

This one is a little unusual because the hoisting idiom here is used for
a partial specialisation that inherits from a complete specialisation.
Of course the hoisting idiom can use an ordinary non-template class as
its base, or it can do this via aggregation.

A good example of this latter version is the normal way that bitset is
implemented.


--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Radoslav Getov

ulæst,
4. dec. 2001, 18.59.5704.12.2001
til
Sungbom Kim <musi...@bawi.org> wrote in message news:<3BFEEAE8...@bawi.org>...
> Can you suggest recommended/discouraged usage of unsigned integers?
>
> I know that unsigned integers are...
> * very good for dealing with bit patterns or bit arrays
> * NOT recommended for just gaining one more bit of storage
> * NOT recommended for ensuring positiveness
>
> Any others?
>
> How about using unsigned integers for quantities that just don't
> go below zero, for example months(1..12), days of month(1..31),
> days of week(0..6 or 1..7), etc. in calendar programs?

It looks like there will be no consensus in this thread. But let me ask you
some questions:

1. If you want to chose to remove one of the types (i.e. signed or unsigned)
from the language, which one you would chose?

2. Why aren't there any unsigned types in some other languages (e.g. Java?)

3. When was the last time you wrote a code using unsigned that wouldn't
work with signed? (Excluding for reasons with compatibility with std
library calls, for which using unsigned looks a big mistake to me.)

4. Is simple code (e.g. using less features/types) better than complex (i.e.
using more features/types) if otherwise there is no difference whatsoever?

Radoslav Getov

Pavel Kuznetsov

ulæst,
5. dec. 2001, 09.52.2005.12.2001
til
Radoslav Getov" <rge...@hotmail.com> wrote:
> 1. If you want to chose to remove one of the types (i.e. signed or unsigned)
> from the language, which one you would chose?

I'd say neither one. Removing signed is no option.
If unsigned is removed, what type would represent bit-pattern?

If you want to chose to remove one of the operations (i.e. + or -, << or >>)
from the language, which one you would chose? :)

> 2. Why aren't there any unsigned types in some other languages (e.g. Java?)

But e.g. Java has unsigned shift instead. IMHO this is even worse
to specify each time which operation to use instead of writing once
that a variable should be treated as unsigned.

> 3. When was the last time you wrote a code using unsigned that wouldn't
> work with signed? (Excluding for reasons with compatibility with std
> library calls, for which using unsigned looks a big mistake to me.)

Yesterday when initialized file position to 3 gigabytes
on 32-bit machine :-)

> 4. Is simple code (e.g. using less features/types) better than complex (i.e.
> using more features/types) if otherwise there is no difference whatsoever?

_if_there_is_no_difference_ whatsoever

--
Pavel Kuznetsov

[ THE REPLY ADDRESS IS NOT GUARANTEED TO LIVE LONGER THAN FEW WEEKS! ]
[ The permanent address is: pavel <dot> kuznetsov <at> mail <dot> ru ]

Pavel Kuznetsov

ulæst,
5. dec. 2001, 09.52.3905.12.2001
til
Terje Sletteb wrote:
> (Note that "unsigned", by itself, is non-standard.)


Mark Wilden <ma...@mwilden.com> wrote:
> Are you sure about that? Because if I have to write


Terje Sletteb wrote:
> No. I meant I've read it, but I've not found it in the C++ draft standard,
> now.
>
> Can anybody else tell what the case is, here?

7.1/3 [dcl.spec] note says:

[Note: since signed, unsigned, long, and short by default imply int,
a type-name appearing after one of those specifiers is treated as
the name being (re)declared. [Example:

void h(unsigned Pc); // void h(unsigned int)
void k(unsigned int Pc); // void k(unsigned int)

--end example] --end note]

Michael S. Terrazas

ulæst,
5. dec. 2001, 16.10.4605.12.2001
til
"Radoslav Getov" <rge...@hotmail.com> wrote in message
news:165529e2.01120...@posting.google.com...
[snip quote]

> It looks like there will be no consensus in this thread. But let me ask
you
> some questions:

The antecedent of "you" above is unclear, so I take it to mean me.

> 1. If you want to chose to remove one of the types (i.e. signed or
unsigned)
> from the language, which one you would chose?

I unsak this question, both types are necessary.

> 2. Why aren't there any unsigned types in some other languages (e.g.
Java?)

Because they don't allow for the different paradigms of design that C++
does. This is not to say that they are bad, they are not suited for some
of the tasks that C++ does exceptionally well.

> 3. When was the last time you wrote a code using unsigned that wouldn't
> work with signed?

Last week.

> 4. Is simple code (e.g. using less features/types) better than complex
(i.e.
> using more features/types) if otherwise there is no difference whatsoever?

This question doesn't make sense to me. Clearly, the use of types
and features makes a difference. To force the usage of a limited
set of types can cause pessimizations that may not be acceptable.
Worse, it may not clearly communicate the intent of the code.

Applying your question to human communication, is a language with
fewer words better than one that has a rich vocabulary? On some
dimensions, perhaps, but I remember working for an organization
that misapplied the Strunk & White style guidelines to all internal
memos. Later they discovered that keeping their vocabulary and
sentence structure to 8th grade level caused severe lapses in
communication and more verbose memos.

--
Mike Terrazas
MLT & Associates

Phil Carmody

ulæst,
6. dec. 2001, 02.41.1606.12.2001
til
Gerhard Menzl wrote:

> Mark Wilden wrote:
> > How could a Counter be signed??
>
> Sigh. You're beginning to split hairs. When iterating through an array
> in a for loop, you typically use the variable that controls the loop
> both as a counter and as an index. You may call your typedef whatever
> you want (Index, CounterIndex, IndexCounter, Iterator); the problem
> remains the same. Others might argue that an index cannot be negative.
> It is really a matter of what different people find intuitive. I
> wouldn't be surprised if there are folks out there who find the concept
> of -3 chickens perfectly natural. <g>

My favourite online shop shows exact (instantaniously correct, hit
reload and they can change) stock levels of all items. When it has 10
more orders than it has items in stock, the stock level _is_ -10, and
that value causes no confusion for anyone. OK, it's MoBos, CPUs etc.
rather than chickens but the principle is the same.
(www.verkkokauppa.com).

I believe in the great baked-bean wars of the mid-nineties (no, this is
not a made-up fairy tale, trust me), supermarkets were using said
product as a loss-leader to attract customers. The price for beans fell
to 9p/tin to 7p, to 5p, to 2p... where could it end? Well, when your
competitor sticks a _0p_ price tag on his beans, the only place to go is
to -2p/tin. Yes, negative prices.

So negatives crop up more often than you would expect...

Phil

Mark Wilden

ulæst,
6. dec. 2001, 02.42.1006.12.2001
til
"Gerhard Menzl" <gerhar...@sea.ericsson.se> wrote in message
news:3C0C8807...@sea.ericsson.se...

> When iterating through an array
> in a for loop, you typically use the variable that controls the loop
> both as a counter and as an index.

I don't. I use an index. I don't need to "count" the array contents at this
point, since I already know how many elements there are. A "loop counter"
doesn't count the items it's iterating over, it counts the number of
iterations. Do you see the difference?

> You may call your typedef whatever
> you want (Index, CounterIndex, IndexCounter, Iterator); the problem
> remains the same.

My point was that you cannot call your typedef whatever you want, and still
have a readable program. I feel the typedef in question was misnamed. Part
of your point was that it was then misused because the programmer relied on
its name, not its definition, to understand it.

> Others might argue that an index cannot be negative.

No, an index clearly _can_ be negative. A count cannot. An index is a
programming artifact--its use is different from ordinals in common parlance.
A count is not different (as I see it)--both humans and computer programmers
agree what it means. If a "count" can go negative, then it's not really a
count at all, and should be renamed accordingly. (All IMHO, of course.)

> It is really a matter of what different people find intuitive. I
> wouldn't be surprised if there are folks out there who find the concept
> of -3 chickens perfectly natural. <g>

I would be extremely surprised, and would be interested in hearing how they
rationalized this "nonintuitive" usage of the English language.

> > You don't include unit testing in that list.
>

> The list was not exhaustive

But it was indicative, I feel. Whenever I see an example like the one you
gave (or even a more contrived example) that seeks to prove a point, it
always seems to assume that the code is never tested. Based on standard
practice, this is actually a pretty reasonable assumption, unfortunately! :)

You presented a situation that you proposed was a problem. In my shop, that
would not be a problem, for several reasons, one of which is the presence of
unit testing. I'm not saying that using unsigned is risk-free, and that's
why I've decided to go back to using ints. I just don't feel your example
was a strong argument in favor of the practice, that's all.

Der indlæses flere opslag.
0 nye opslag