signed/unsigned..?

S

Søren Johansen

Hi,

in Large Scale c++ Design, John Lakos suggests that you should avoid the
"unsigned" keyword and use regular ints. Now I know that this book is
considered mostly outdated and I do use namespaces (which he also suggests
avoiding) and other things, but this particular topic has me puzzled.

The problem is that stl has a lot of size_t types that are unsigned and
since I run a no-warning policy, this forces me to do a lot of casting if
using pure int's. On the other hand, when you start to have unsigned
variables, I find that you risk getting errors that can be extremely subtle
and hard to track down.

Any advice and experience appreciated.

Søren
 
H

Hendrik Belitz

Søren Johansen said:
Hi,

in Large Scale c++ Design, John Lakos suggests that you should avoid the
"unsigned" keyword and use regular ints.

I don't agree with this. Especially for range checking purposes the usage of
unsigned values is preferable. Just look at the following example.

int i = ...
if ( i > 0 || i < 1000 ) doWhateverYouLike

using unsigned int this becomes
unsigned int = ...
if ( i < 1000 ) doWhateverYouLike
 
J

Josephine Schafer

Søren Johansen said:
Hi,

in Large Scale c++ Design, John Lakos suggests that you should avoid the
"unsigned" keyword and use regular ints. Now I know that this book is
considered mostly outdated and I do use namespaces (which he also suggests
avoiding) and other things, but this particular topic has me puzzled.

The problem is that stl has a lot of size_t types that are unsigned and
since I run a no-warning policy, this forces me to do a lot of casting if
using pure int's. On the other hand, when you start to have unsigned
variables, I find that you risk getting errors that can be extremely subtle
and hard to track down.

I don't know in what context Lakos has made the statement.
But it's not correct to assume size_t is unsigned int or anything else.
Take example of std::string.
#include <string>
int main()
{
std::string Buffer("abc");
std::string::size_type loop = Buffer.length ();
}

If you take Buffer.length() to fit into an unsigned int, the result may/may not
be correct depending on whether
std::string::size_type is actually unsigned int or not. So to be safe always
use the size types provided by the class.

HTH,
J.Schafer

..
 
L

lilburne

Hendrik said:
I don't agree with this. Especially for range checking purposes the usage of
unsigned values is preferable. Just look at the following example.

int i = ...
if ( i > 0 || i < 1000 ) doWhateverYouLike

using unsigned int this becomes
unsigned int = ...
if ( i < 1000 ) doWhateverYouLike

int i = ...

assert(i >= 0);

works just as well and causes an error if the constraint is violated.
 
H

Harald Grossauer

Hendrik said:
I don't agree with this. Especially for range checking purposes the usage
of unsigned values is preferable. Just look at the following example.

That's what I thought once too. But then it took me two days to find the
following bug in my program:

unsigned int i;
/*
....
lots of other code
.....
*/
for( i = nMax; i>0; --i ) {...
 
S

Søren Johansen

I don't know in what context Lakos has made the statement.
But it's not correct to assume size_t is unsigned int or anything else.
Take example of std::string.
#include <string>
int main()
{
std::string Buffer("abc");
std::string::size_type loop = Buffer.length ();
}

If you take Buffer.length() to fit into an unsigned int, the result may/may not
be correct depending on whether
std::string::size_type is actually unsigned int or not. So to be safe always
use the size types provided by the class.

I realize this but there are some things that I dislike about it.
Consider this (made up) simple example:

class Store
{
std::vector<int> _somevector;
..other stuff..

public:
std::vector::size_type GetElementCount() { return _somevector.size(); }
void DoSomethingToElement(std::vector::size_type index);
};

Here, it seems to me that having to use the std::vector::size_type reveals
more implementation than I like in the interface. Furthermore, what if you
were to use the same index for two containers of different types?

Søren
 
S

Søren Johansen

int i = ...
if ( i > 0 || i < 1000 ) doWhateverYouLike

using unsigned int this becomes
unsigned int = ...
if ( i < 1000 ) doWhateverYouLike

Yes but if you only want to make sure i is positive, and i has been assigned
to some unsigned value, you would have to check for i < 2147483647..
Wouldn't you? My point is that it seems that unsigned values don't really
solve the problem that they appear to. Yes, an unsigned value can never be
negative but assigning a signed value to it or comparing with a signed value
produces weird results.
The argument about the one extra bit that is gained seems to me to only be
viable in very few, special cases. Your argument is better but on the other
hand it can produce errors that are hard to identify.

Søren
 
K

Karl Heinz Buchegger

Harald said:
That's what I thought once too. But then it took me two days to find the
following bug in my program:

unsigned int i;
/*
...
lots of other code
....
*/
for( i = nMax; i>0; --i ) {...

:)
There is no problem with that. But I know what you mean.
I myself have been bitten lots of times by turning

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

around (because eg. I wanted to change the direction
in which an array is traversed) to:

for( i = nMax - 1; i >= 0; --i )

if i is unsigned this will no longer work :)
 
R

Rob Williscroft

Harald Grossauer wrote in
That's what I thought once too. But then it took me two days to find
the following bug in my program:

unsigned int i;
/*
...
lots of other code
....
*/
for( i = nMax; i>0; --i ) {...

There are several other options that could help here:

1) Get a better compiler and switch all warnings on.

2) Recode as:

for( unsigned i = nMax; i>0; --i ) {

3) Don't call unsigned int's i (maybe u).

4) Don't write computer programmes.

Only (4) is guaranted to work.

Rob.
 
C

Cy Edmunds

Søren Johansen said:
Hi,

in Large Scale c++ Design, John Lakos suggests that you should avoid the
"unsigned" keyword and use regular ints. Now I know that this book is
considered mostly outdated and I do use namespaces (which he also suggests
avoiding) and other things, but this particular topic has me puzzled.

The problem is that stl has a lot of size_t types that are unsigned and
since I run a no-warning policy, this forces me to do a lot of casting if
using pure int's. On the other hand, when you start to have unsigned
variables, I find that you risk getting errors that can be extremely subtle
and hard to track down.

Any advice and experience appreciated.

Søren

Sorry, I have no useful advice. I have the same problem and use casting to
int far more than I would like to.
 
R

Rob Williscroft

Karl Heinz Buchegger wrote in

Indeed, I missed this in my first response.
There is no problem with that. But I know what you mean.
I myself have been bitten lots of times by turning

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

around (because eg. I wanted to change the direction
in which an array is traversed) to:

for( i = nMax - 1; i >= 0; --i )

if i is unsigned this will no longer work :)

It has become atomatic for me to do:

for ( i = nMax; i-- >= 0; )


Iterators (as a concept) help here as they force you to think
in terms of the fail condition, rather that the success condition,
"until" rather than "while" maybe.

for ( i = begin(); i != end(); ++i ) reverses to
for ( i = end(); i-- != begin(); )

Though it would really be:

for( i = end(); i != begin(); )
{
--i;
// ...
}

Just in case the iterator asserts on --begin().

So we could write:

for ( i = 0; i != nMax; ++i ) and
for ( i = nMax; i-- != 0; )

Iterators have a similar problem to unsigned, in that you can't
meaningfully decrement to an element before the begining.

Rob.
 
R

Rolf Magnus

Rob said:
Karl Heinz Buchegger wrote in

Indeed, I missed this in my first response.


It has become atomatic for me to do:

for ( i = nMax; i-- >= 0; )


Iterators (as a concept) help here as they force you to think
in terms of the fail condition, rather that the success condition,
"until" rather than "while" maybe.

for ( i = begin(); i != end(); ++i ) reverses to
for ( i = end(); i-- != begin(); )

Though it would really be:

for( i = end(); i != begin(); )
{
--i;
// ...
}

Just in case the iterator asserts on --begin().

So we could write:

for ( i = 0; i != nMax; ++i ) and
for ( i = nMax; i-- != 0; )

Iterators have a similar problem to unsigned, in that you can't
meaningfully decrement to an element before the begining.

That's why there are reverse iterators:

for ( i = begin(); i != end(); ++i ) reverses to
for ( i = rbegin(); i != rend(); ++i)
 
R

Rolf Magnus

Søren Johansen said:
I realize this but there are some things that I dislike about it.
Consider this (made up) simple example:

class Store
{
std::vector<int> _somevector;
..other stuff..

public:
std::vector::size_type GetElementCount() { return
_somevector.size(); } void
DoSomethingToElement(std::vector::size_type index);
};

Here, it seems to me that having to use the std::vector::size_type
reveals more implementation than I like in the interface.

Simple solution:

class Store
{
std::vector<int> _somevector;
..other stuff..

public:
typedef std::vector<int>::size_type size_type;

size_type GetElementCount() { return _somevector.size(); }
void DoSomethingToElement(size_type index);
};

Furthermore, what if you were to use the same index for two containers
of different types?

What for?
 
R

Risto Lankinen

Karl Heinz Buchegger said:
Thank's for that! I never realized that solution to this problem.

Thanks for what? If 'i' is indeed unsigned, it still doesn't work.

Cheers!

- Risto -
 
R

Rob Williscroft

Risto Lankinen wrote in
Thanks for what? If 'i' is indeed unsigned, it still doesn't work.

Thanks for the correction, I should have writen:

for ( i = nMax; i-- > 0; )

Though I did get it write later in the post:

for ( i = nMax; i-- != 0; )

It maybe that the single point of failure in the second version is
less error prone (though it could have been a cut paste typo', I
really can't remember).

Rob.
 
B

Bob Hairgrove

unsigned int i;
/*
...
lots of other code
....
*/
for( i = nMax; i>0; --i ) {...

Well, Borland C++ Builder 5 (for one) will issue a helpful warning
here: "the condition is always true" ...

It also helps to avoid using variable names like "i" if you need them
in scope for more than a couple of lines or so.
 

Ask a Question

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

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

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top