By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,908 Members | 2,055 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,908 IT Pros & Developers. It's quick & easy.

negative number evaluating greater than string.size()

P: n/a
Hi, below is example code which demonstrates a problem I have encountered.
When passing a number to a function I compare it with a string's size and
then take certain actions, unfortunately during the testing of it I
discovered that negative numbers were being treated as if they were > 0. I
compiled the following on mingw compiler/dev c++/windows xp.

If I replace string.size() for a ordinary number it behaves as expected? I
notice string.size() returns size type and not an int but how do I deal with
that?

Thanks in advance for any help

#include <iostream>
#include <stdlib.h>
#include <string>
using namespace std;

void something(int);

int main()
{
something(-1);
system("PAUSE");
return 0;
}

void something(int number) {
string str = "sdfjksdflksdjfkjsklfjsklfj";
if(number < str.size()) { cout << " hello" << endl; }
else { cout << " eek" << endl; }
}
Jul 22 '05 #1
Share this Question
Share on Google+
25 Replies


P: n/a
Jason wrote:
Hi, below is example code which demonstrates a problem I have encountered.
When passing a number to a function I compare it with a string's size and
then take certain actions, unfortunately during the testing of it I
discovered that negative numbers were being treated as if they were > 0. I
compiled the following on mingw compiler/dev c++/windows xp.

If I replace string.size() for a ordinary number it behaves as expected? I
notice string.size() returns size type and not an int but how do I deal with
that?

Thanks in advance for any help


GCC sez:

signed_probs.cpp: In function `void something(int)':
signed_probs.cpp:17: warning: comparison between signed and unsigned
integer expressions

Changing line 17 to :

if(number < static_cast<int>(str.size())) { cout << " hello" << endl; }

solves the problem.
Jul 22 '05 #2

P: n/a

"Jason" <ja***********@btinternet.com> wrote in message
news:c1**********@titan.btinternet.com...
Hi, below is example code which demonstrates a problem I have encountered.
When passing a number to a function I compare it with a string's size and
then take certain actions, unfortunately during the testing of it I
discovered that negative numbers were being treated as if they were > 0. I compiled the following on mingw compiler/dev c++/windows xp.

If I replace string.size() for a ordinary number it behaves as expected? I notice string.size() returns size type and not an int but how do I deal with that?


Suggest you read the recent thread 'time to get rid of unsigned?', started
on 17/02/04.

john
Jul 22 '05 #3

P: n/a

"Gianni Mariani" <gi*******@mariani.ws> wrote in message
news:c1********@dispatch.concentric.net...
Jason wrote:
Hi, below is example code which demonstrates a problem I have encountered. When passing a number to a function I compare it with a string's size and then take certain actions, unfortunately during the testing of it I
discovered that negative numbers were being treated as if they were > 0. I compiled the following on mingw compiler/dev c++/windows xp.

If I replace string.size() for a ordinary number it behaves as expected? I notice string.size() returns size type and not an int but how do I deal with that?

Thanks in advance for any help


GCC sez:

signed_probs.cpp: In function `void something(int)':
signed_probs.cpp:17: warning: comparison between signed and unsigned
integer expressions

Changing line 17 to :

if(number < static_cast<int>(str.size())) { cout << " hello" << endl; }

solves the problem.


Of course this is what the OP should do, but notice that the solution
effectively rules out strings where size() > INT_MAX. So why design for such
strings in the first place? Why not have size() return an int?

john

Jul 22 '05 #4

P: n/a
John Harrison wrote:
"Gianni Mariani" <gi*******@mariani.ws> wrote in message
news:c1********@dispatch.concentric.net...

signed_probs.cpp: In function `void something(int)':
signed_probs.cpp:17: warning: comparison between signed and unsigned
integer expressions

Changing line 17 to :

if(number < static_cast<int>(str.size())) { cout << " hello" << endl; }

solves the problem.

Of course this is what the OP should do, but notice that the solution
effectively rules out strings where size() > INT_MAX. So why design for such
strings in the first place? Why not have size() return an int?


Because its more flexible to have a type where someone can
hold a string thats over 2Gb in size. I remember something
like this being used as a justification for making size_t
unsigned some 15 years back, either in GCC documentation or
the "Standard C library", in relation to malloc().

Naturally someone will tell you that you should be coding
everything that deals with sizes and lengths with size_t.
Jul 22 '05 #5

P: n/a

"lilburne" <li******@godzilla.net> wrote in message
news:c1*************@ID-179504.news.uni-berlin.de...
John Harrison wrote:
"Gianni Mariani" <gi*******@mariani.ws> wrote in message
news:c1********@dispatch.concentric.net...

signed_probs.cpp: In function `void something(int)':
signed_probs.cpp:17: warning: comparison between signed and unsigned
integer expressions

Changing line 17 to :

if(number < static_cast<int>(str.size())) { cout << " hello" << endl; }
solves the problem.
Of course this is what the OP should do, but notice that the solution
effectively rules out strings where size() > INT_MAX. So why design for such strings in the first place? Why not have size() return an int?


Because its more flexible to have a type where someone can
hold a string thats over 2Gb in size. I remember something
like this being used as a justification for making size_t
unsigned some 15 years back, either in GCC documentation or
the "Standard C library", in relation to malloc().


Interestingly the following code

int main()
{
std::string s;
std::cout << std::hex << s.max_size() << '\n';
}

when compiled with gcc 3.3.1 prints

3ffffffc

I don't think its a serious limitation to restrict yourself to strings which
occupy less than half of the available memory.

Naturally someone will tell you that you should be coding
everything that deals with sizes and lengths with size_t.


But what happens when you need to subtract one size from another? What type
should be used to hold the type of that operation? I don't think there is a
good answer.

john
Jul 22 '05 #6

P: n/a
> What type should be used to hold the type of that operation?

I meant

What type should be used to hold the result of that operation?
Jul 22 '05 #7

P: n/a
lilburne wrote:
Of course this is what the OP should do, but notice that the solution
effectively rules out strings where size() > INT_MAX. So why design
for such strings in the first place? Why not have size() return an
int?


Because its more flexible to have a type where someone can
hold a string thats over 2Gb in size.


I think it's not. You'd run into troubles if you need to calculate
offsets between two characters in your string. That offset might be
negative. Now you can't represent all possible offests anymore, no
matter whether you make the type for that offset signed or unsigned.
And further, if you mix signed and unsigned in your calculations, you
have to be very careful.

Jul 22 '05 #8

P: n/a
"John Harrison" <jo*************@hotmail.com> wrote in news:c13cvl$1dskq6$1
@ID-196037.news.uni-berlin.de:
What type should be used to hold the type of that operation?


I meant

What type should be used to hold the result of that operation?


size_t, assuming the programmer has done the sane thing and checked that
they are actually subtracting the smaller from the larger.
Jul 22 '05 #9

P: n/a
John Harrison wrote:
...
Changing line 17 to :

if(number < static_cast<int>(str.size())) { cout << " hello" << endl; }

solves the problem.


Of course this is what the OP should do, but notice that the solution
effectively rules out strings where size() > INT_MAX. So why design for such
strings in the first place? Why not have size() return an int?
...


In my opinion, using a signed type to store an unsigned quantity is a
low-level design error. For this reason, in many practical applications
signed types in C/C++ are much less useful than unsigned types. And
'size()' must return an unsigned value.

As for correcting the OP's code, I would suggest doing it differently

if (number < 0 || (std::string::size_type) number < str.size())
{ cout << " hello" << endl; }

--
Best regards,
Andrey Tarasevich

Jul 22 '05 #10

P: n/a
Rolf Magnus wrote:
lilburne wrote:

Of course this is what the OP should do, but notice that the solution
effectively rules out strings where size() > INT_MAX. So why design
for such strings in the first place? Why not have size() return an
int?

Because its more flexible to have a type where someone can
hold a string thats over 2Gb in size.

I think it's not.

I think so too.

You'd run into troubles if you need to calculate
offsets between two characters in your string. That offset might be
negative. Now you can't represent all possible offests anymore, no
matter whether you make the type for that offset signed or unsigned.
And further, if you mix signed and unsigned in your calculations, you
have to be very careful.


I think it was for the reasons of inadvertantly mixing
signed and unsigned that Lakos recommended avoiding unsigned
in interfaces in "Large Scale C++".

Jul 22 '05 #11

P: n/a

"Andre Kostur" <nn******@kostur.net> wrote in message
news:Xn*******************************@207.35.177. 135...
"John Harrison" <jo*************@hotmail.com> wrote in news:c13cvl$1dskq6$1 @ID-196037.news.uni-berlin.de:
What type should be used to hold the type of that operation?


I meant

What type should be used to hold the result of that operation?


size_t, assuming the programmer has done the sane thing and checked that
they are actually subtracting the smaller from the larger.


It gets very tedious after a while.

size_t size_a = ...;
size_t size_b = ...;
size diff;
bool a_is_bigger;
if (a > b)
{
diff = size_a - size_b;
a_is_bigger = true;
}
else
{
diff = size_b - size_a;
a_is_bigger = false;
}
process_diff(diff, a_is_bigger);

and hence its prone to errors, as we have all seen. In fact I very rarely
see code that takes this much trouble. It would be easier if size_t was
defined as a signed integer, and not a great deal would have been lost.

john

Jul 22 '05 #12

P: n/a
John Harrison wrote:
...
It would be easier if size_t was
defined as a signed integer, and not a great deal would have been lost.
...


It wouldn't solve anything. It would just made the problem less obvious.
In general case the difference between two signed integers does not fit
into the range of the same signed integer type. The resultant signed
type must be at least one bit longer than original types.

--
Best regards,
Andrey Tarasevich

Jul 22 '05 #13

P: n/a

"Andrey Tarasevich" <an**************@hotmail.com> wrote in message
news:Ft********************@comcast.com...
John Harrison wrote:
...
It would be easier if size_t was
defined as a signed integer, and not a great deal would have been lost.
...


It wouldn't solve anything. It would just made the problem less obvious.
In general case the difference between two signed integers does not fit
into the range of the same signed integer type. The resultant signed
type must be at least one bit longer than original types.


When that integer represents the size of something, it can only be positive
or zero. If it always possible to subtract two such positive signed numbers
without overflow. That's obvious isn't it?

john
Jul 22 '05 #14

P: n/a
John Harrison wrote:
> ...
> It would be easier if size_t was
> defined as a signed integer, and not a great deal would have been lost.
> ...


It wouldn't solve anything. It would just made the problem less obvious.
In general case the difference between two signed integers does not fit
into the range of the same signed integer type. The resultant signed
type must be at least one bit longer than original types.


When that integer represents the size of something, it can only be positive
or zero. If it always possible to subtract two such positive signed numbers
without overflow. That's obvious isn't it?
...


Yes, but the trade-off in this case is that you can only use half of the
type's range.

--
Best regards,
Andrey Tarasevich

Jul 22 '05 #15

P: n/a
John Harrison wrote:
"Gianni Mariani" <gi*******@mariani.ws> wrote in message
news:c1********@dispatch.concentric.net...
Jason wrote:
Hi, below is example code which demonstrates a problem I have encountered. When passing a number to a function I compare it with a string's size and then take certain actions, unfortunately during the testing of it I discovered that negative numbers were being treated as if they were > 0. I compiled the following on mingw compiler/dev c++/windows xp. If I replace string.size() for a ordinary number it behaves as expected? I
notice string.size() returns size type and not an int but how do I deal with that? Thanks in advance for any help

<reinserted>

void something(int number) {
if(number < str.size()) { /*...*/ }
}

</>
GCC sez:

signed_probs.cpp: In function `void something(int)':
signed_probs.cpp:17: warning: comparison between signed and unsigned
integer expressions

Changing line 17 to :

if(number < static_cast<int>(str.size())) { cout << " hello" << endl; }

solves the problem.

Of course this is what the OP should do,


No, an unnecessary cast is not what the OP should do. The problem is
that a signed "number" is being compared to an unsigned "size." "int"
and "string::size_type" are not the same thing; they are not always
comparable. A more reasonable solution would be for "number" to be of
string::size_type in the first place, or of a signed type that knows how
to compare itself with string::size_type.

Jul 22 '05 #16

P: n/a
lilburne wrote:
I think it was for the reasons of inadvertantly mixing
signed and unsigned that Lakos recommended avoiding unsigned
in interfaces in "Large Scale C++".


Same for Stroustup in TC++PL. Strange enough that size_t is unsinged,
since Stroustrup probably had to do something with it. In the book, he
writes:

"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."
Jul 22 '05 #17

P: n/a


Jeff Schwab wrote:

No, an unnecessary cast is not what the OP should do. The problem is
that a signed "number" is being compared to an unsigned "size." "int"
and "string::size_type" are not the same thing; they are not always
comparable. A more reasonable solution would be for "number" to be of
string::size_type in the first place, or of a signed type that knows how
to compare itself with string::size_type.


Naturally! And std::vector::size_type, std::list::size_type,
std::deque::size_type, std::set::size_type, std::map::size_type, etc,
whenever dealing with the corresponding class. Maybe they'll all be the
same underlaying type, but who can tell?

Jul 22 '05 #18

P: n/a
lilburne wrote:


Jeff Schwab wrote:

No, an unnecessary cast is not what the OP should do. The problem is
that a signed "number" is being compared to an unsigned "size." "int"
and "string::size_type" are not the same thing; they are not always
comparable. A more reasonable solution would be for "number" to be of
string::size_type in the first place, or of a signed type that knows
how to compare itself with string::size_type.

Naturally! And std::vector::size_type, std::list::size_type,
std::deque::size_type, std::set::size_type, std::map::size_type, etc,
whenever dealing with the corresponding class.


That's right.
Maybe they'll all be the
same underlaying type, but who can tell?


A specialized template can.

Jul 22 '05 #19

P: n/a
Andrey Tarasevich wrote:
John Harrison wrote:
...
Changing line 17 to :

if(number < static_cast<int>(str.size())) { cout << " hello" <<
endl; }

solves the problem.


Of course this is what the OP should do, but notice that the solution
effectively rules out strings where size() > INT_MAX. So why design
for such strings in the first place? Why not have size() return an
int? ...


In my opinion, using a signed type to store an unsigned quantity is a
low-level design error.


In mine, it's a design error to use an unsigned type if you don't have a
very good reason to do so. That you only want to store non-negative
values is not such a reason.
Why is there no unsigned floating point type, just for the case you want
to store only postive values?

Jul 22 '05 #20

P: n/a
Rolf Magnus wrote:
...
In my opinion, using a signed type to store an unsigned quantity is a
low-level design error.
In mine, it's a design error to use an unsigned type if you don't have a
very good reason to do so. That you only want to store non-negative
values is not such a reason.


Well, looks like we have different opinions on the subject.
Why is there no unsigned floating point type, just for the case you want
to store only postive values?


For several reasons. It is much more difficult to provide
implementation-level support for an additional floating-point type than
for an additional integral type in situations when the underlying
hardware does not support it. Additionally, aside from purely conceptual
reasons, there is very little benefit from one extra mantissa (or
exponent) bit in a floating-point type. Under these circumstances, since
most hardware does not provide support for unsigned floating-point
types, it is not reasonable to force these types into language.

BTW, the reasons for domination of signed integral types in certain
arithmetical contexts in C (inherited into C++, like integral promotions
from smaller types) are probably very similar.

--
Best regards,
Andrey Tarasevich

Jul 22 '05 #21

P: n/a
>
Suggest you read the recent thread 'time to get rid of unsigned?', started
on 17/02/04.

john


I read all the whining about unsigned, and still disagree....

Regardless, what sense does it make to have a string with size < 0?
Furthermore, he should have been using
void something(std::string::size_type)
to start with.

In my mind, this is just a problem of people not reading the standard
documentation.

The least programmers should do is see the header files to understand
what types are being used, not just trust their instincts.
Jul 22 '05 #22

P: n/a

"Jorge Rivera" <jo*****@rochester.rr.com> wrote in message
news:1N*******************@twister.nyroc.rr.com...

Suggest you read the recent thread 'time to get rid of unsigned?', started on 17/02/04.

john
I read all the whining about unsigned, and still disagree....

Regardless, what sense does it make to have a string with size < 0?


That's not the point. Apparaently both Stroustrup and Lakos recomend
avoiding using unsigned for the size of something because of the potential
overflow problems, particularly (in my view) when one unsigned quantity has
to be subtracted from another.
Furthermore, he should have been using
void something(std::string::size_type)
to start with.
Maybe but you cannot know the problem he was working on.

In my mind, this is just a problem of people not reading the standard
documentation.

The least programmers should do is see the header files to understand
what types are being used, not just trust their instincts.


Can't disagree with that.

john
Jul 22 '05 #23

P: n/a
Andrey Tarasevich <an**************@hotmail.com> wrote in message news:<10*************@news.supernews.com>...
John Harrison wrote:
...
Changing line 17 to :

if(number < static_cast<int>(str.size())) { cout << " hello" << endl; }

solves the problem.


Of course this is what the OP should do, but notice that the solution
effectively rules out strings where size() > INT_MAX. So why design for such
strings in the first place? Why not have size() return an int?
...


In my opinion, using a signed type to store an unsigned quantity is a
low-level design error.


What does unsigned gain you? If you use signed and write code with a
bug, you could end up calculating someone's age as -1 years. If you
use unsigned and write the same code with the same bug you end up with
the age as 4294967295 years (assuming 32 bits as an example). Who
cares that one of those numbers happens to be >0? They are both as
wrong as the other. The code needs to be fixed whether age is signed
or unsigned, and once it is fixed, it will work whether age is signed
or unsigned.

--
GJD
Jul 22 '05 #24

P: n/a
Jorge Rivera <jo*****@rochester.rr.com> wrote in message news:<1N*******************@twister.nyroc.rr.com>. ..

Suggest you read the recent thread 'time to get rid of unsigned?', started
on 17/02/04.

john
I read all the whining about unsigned, and still disagree....

Regardless, what sense does it make to have a string with size < 0?


You missed the point. With a signed string size type, any code that
ends up with a size < 0 has a bug. If that same code had been written
with an unsigned string size type, it would still have a bug. The
garbage size value would now happen to be > 0, but so what? That
doesn't make the code any more correct. It is the same bug,
manifesting itself in a different way.

--
GJD
Furthermore, he should have been using
void something(std::string::size_type)
to start with.

In my mind, this is just a problem of people not reading the standard
documentation.

The least programmers should do is see the header files to understand
what types are being used, not just trust their instincts.

Jul 22 '05 #25

P: n/a
>
You missed the point. With a signed string size type, any code that
ends up with a size < 0 has a bug. If that same code had been written
with an unsigned string size type, it would still have a bug. The
garbage size value would now happen to be > 0, but so what? That
doesn't make the code any more correct. It is the same bug,
manifesting itself in a different way.


The point is simple, read the documentation, read the correct behavior
of std::string, use it appropriately.

std::string::size_type std::string::size()

can not return a negative number. If anything, functions within
std::string will return std::string::npos, and I doubt there is any
situtation in which std::size() would return it.

Any other assumptions about values returned by string are just that,
assumptions. The behavior of the class is what it is, and we all should
just play by its rules, not whine weahter the implementation is signed
or unsigned.

JLR

Jul 22 '05 #26

This discussion thread is closed

Replies have been disabled for this discussion.