negative number evaluating greater than string.size()

Discussion in 'C++' started by Jason, Feb 19, 2004.

  1. Jason

    Jason Guest

    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; }
    }
     
    Jason, Feb 19, 2004
    #1
    1. Advertising

  2. 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.
     
    Gianni Mariani, Feb 19, 2004
    #2
    1. Advertising

  3. "Jason" <> wrote in message
    news:c12qn6$ik2$...
    > 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
     
    John Harrison, Feb 19, 2004
    #3
  4. "Gianni Mariani" <> wrote in message
    news:c12sm0$...
    > 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
     
    John Harrison, Feb 19, 2004
    #4
  5. Jason

    lilburne Guest

    John Harrison wrote:

    > "Gianni Mariani" <> wrote in message
    > news:c12sm0$...
    >
    >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.
     
    lilburne, Feb 19, 2004
    #5
  6. "lilburne" <> wrote in message
    news:c136e9$1de8mh$-berlin.de...
    > John Harrison wrote:
    >
    > > "Gianni Mariani" <> wrote in message
    > > news:c12sm0$...
    > >
    > >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
     
    John Harrison, Feb 19, 2004
    #6
  7. > 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?
     
    John Harrison, Feb 19, 2004
    #7
  8. Jason

    Rolf Magnus Guest

    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.
     
    Rolf Magnus, Feb 19, 2004
    #8
  9. Jason

    Andre Kostur Guest

    "John Harrison" <> 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.
     
    Andre Kostur, Feb 19, 2004
    #9
  10. 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
     
    Andrey Tarasevich, Feb 20, 2004
    #10
  11. Jason

    lilburne Guest

    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++".
     
    lilburne, Feb 20, 2004
    #11
  12. "Andre Kostur" <> wrote in message
    news:Xns94949E1E88AFEnntpspamkosturnet@207.35.177.135...
    > "John Harrison" <> 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
     
    John Harrison, Feb 20, 2004
    #12
  13. 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
     
    Andrey Tarasevich, Feb 20, 2004
    #13
  14. "Andrey Tarasevich" <> wrote in message
    news:...
    > 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
     
    John Harrison, Feb 20, 2004
    #14
  15. 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
     
    Andrey Tarasevich, Feb 20, 2004
    #15
  16. Jason

    Jeff Schwab Guest

    John Harrison wrote:
    > "Gianni Mariani" <> wrote in message
    > news:c12sm0$...
    >
    >>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.
     
    Jeff Schwab, Feb 20, 2004
    #16
  17. Jason

    Rolf Magnus Guest

    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."
     
    Rolf Magnus, Feb 20, 2004
    #17
  18. Jason

    lilburne Guest

    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?
     
    lilburne, Feb 20, 2004
    #18
  19. Jason

    Jeff Schwab Guest

    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.
     
    Jeff Schwab, Feb 20, 2004
    #19
  20. Jason

    Rolf Magnus Guest

    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?
     
    Rolf Magnus, Feb 20, 2004
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. falcon
    Replies:
    10
    Views:
    19,260
    Roedy Green
    Feb 24, 2006
  2. Martin
    Replies:
    9
    Views:
    2,962
    Karl Heinz Buchegger
    Nov 15, 2004
  3. lazy

    string size greater than page size?

    lazy, Apr 27, 2007, in forum: C Programming
    Replies:
    3
    Views:
    386
    Army1987
    Apr 27, 2007
  4. Dwight Army of Champions
    Replies:
    4
    Views:
    2,904
    John H.
    Mar 17, 2010
  5. Peng Yu
    Replies:
    3
    Views:
    306
    Dr.Ruud
    Jun 19, 2010
Loading...

Share This Page