Thread: Should I cast to long or unsigned long?

  1. #1
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545

    Should I cast to long or unsigned long?

    I have code that does something like this:
    Code:
    void func( char* str, unsigned long len )
    {
        char* pos = str + someNumber;
        ...
        while ( pos - str < len )
        {
            ...
        }
    }
    This produces a signed/unsigned mismatch for the < comparison, so to get rid of that warning, I need to cast one side to the other.

    I'm not sure if it's better in this case to go with:
    Code:
    assert( len <= LONG_MAX );
    while ( pos - str < static_cast<long>(len) )
    or
    Code:
    while ( static_cast<unsigned long>(pos - str) < len )
    {
         assert( (pos - str) >= 0 );
        ...
    }
    It's mainly the result of char* - char* that I'm wondering about. You can't have a negative pointer value, so I'm not sure why the compiler thinks (pos - str) is signed?

  2. #2
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Wouldn't
    Code:
    while ( pos < len + str)
    do the same thing and eliminate the warning?

    It's mainly the result of char* - char* that I'm wondering about. You can't have a negative pointer value, so I'm not sure why the compiler thinks (pos - str) is signed?
    Pointer - pointer returns distance, and the first pointer may be less than the second. (Since you know more than the compiler here - that this won't be the case - the cast to unsigned should be OK.)

    And you can use negative indices:
    Code:
    int main()
    {
        int a[3];
        int* b = &a[1];
        b[-1] = 10;
    }
    Last edited by anon; 05-27-2008 at 09:49 AM.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    pos - str is a ptrdiff_t by type.

    Assuming someNumber is positive, then pos-str is going to be positive as well, so that seems the safer cast to me.

    Perhaps consider using just array subscripts rather than manipulating the pointers directly. A modern compiler shouldn't have too much trouble making it efficient.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Pointers are indeed "signless" (not quite the same as unsigned).

    But the difference between two pointers is not certain to be, what if you do:
    Code:
    char *t = "abcdef";
    char *p1 = strchr(t, 'a');
    char *p2 = strchr(t, 'f');
    
    int x = p1 - p2; // Should be -5.
    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  5. #5
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by matsp View Post
    Pointers are indeed "signless" (not quite the same as unsigned).

    But the difference between two pointers is not certain to be, what if you do:
    Code:
    char *t = "abcdef";
    char *p1 = strchr(t, 'a');
    char *p2 = strchr(t, 'f');
    
    int x = p1 - p2; // Should be -5.
    --
    Mats
    Yes, logically it could be negative in that case, but if (p1 - p2) is unsigned, it would be a huge number instead of a negative number, which is why this particular case confuses me a bit.

    So are you saying that (p1 - p2) can be either signed or unsigned depending on the context?
    In that case, what about something like this (with 32-bit pointers):
    Code:
    char* p1 = (char*)0x00000001;
    char* p2 = (char*)0xFFFFFFCC;
    int x = p1 - p2;

  6. #6
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    1. You are only meant to compare/do math on pointers that point to the same block of memory - so one pointer pointing to 0xFFFFFFCC and another pointing to 0x00000001 are either a huge block of memory (near enough 4GB), in which case the 0x00000001 pointer is really about -4GB away from the other. If they are different memory blocks, then there's, technically, no valid difference between them.

    2. It is perfectly valid to get negative differences between pointers - it can be useful at some times. Having ptrdiff_t an unsigned value would not always work.

    If you really want to work on bigger memory blocks than 2GB, then your ptrdiff_t would need to be 33 bits or more.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  7. #7
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by matsp View Post
    1. You are only meant to compare/do math on pointers that point to the same block of memory - so one pointer pointing to 0xFFFFFFCC and another pointing to 0x00000001 are either a huge block of memory (near enough 4GB), in which case the 0x00000001 pointer is really about -4GB away from the other. If they are different memory blocks, then there's, technically, no valid difference between them.

    2. It is perfectly valid to get negative differences between pointers - it can be useful at some times. Having ptrdiff_t an unsigned value would not always work.

    If you really want to work on bigger memory blocks than 2GB, then your ptrdiff_t would need to be 33 bits or more.

    --
    Mats
    OK, so in that case, since the pointer difference could be negative, casting to len to long would be the better choice, right?

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by cpjust View Post
    OK, so in that case, since the pointer difference could be negative, casting to len to long would be the better choice, right?
    But it will only be negative if the second pointer is BEFORE the first pointer in the subtraction, and you sort of should know whether it is or not. It is safe to cast a positive signed value to unsigned. Casting an unsigned to signed can have bad consequences [but only if the value is over 2G, which for string lengths and such is unlikely].

    Adding an assert to make sure would be a safe thing to do.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Heap corruption using zlib inflate
    By The Wazaa in forum C++ Programming
    Replies: 0
    Last Post: 03-29-2007, 12:43 PM
  2. Need Help Please
    By YouShallNotPass in forum C++ Programming
    Replies: 3
    Last Post: 08-22-2006, 11:22 AM
  3. How do i un-SHA1 hash something..
    By willc0de4food in forum C Programming
    Replies: 4
    Last Post: 09-14-2005, 05:59 AM
  4. Knight's Tour Recursion Problem
    By thephreak6 in forum C++ Programming
    Replies: 1
    Last Post: 10-14-2003, 09:18 AM
  5. can someone check this out and let me know ?
    By javaz in forum C Programming
    Replies: 5
    Last Post: 01-21-2002, 02:13 PM