Thread: mixing unsigned and signed

  1. #1
    Registered User
    Join Date
    Jan 2007
    Posts
    330

    mixing unsigned and signed

    One thing that always annoyed me about C and C++ is that sometimes you are forced to mix unsigned and signed types. For instance when you pass an array to a function and to be correct you better pass a size_t as the size too.

    Code:
    void func(OBJ results[3], size_t n) {	
      for (int i = 0; i < n; i++)  {
        if (results[i] != 0)
          results[i].SetVal(i);
      }
    }
    }
    Then if you loop through the array with an int you get the warning that you're mixing unsigned and signed types but if you change it to size_t and the SetVal expects an int then you get the warning there.

    How do you guys solve this?

  2. #2
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    if I cannot make setVal that accepts size_t
    I will use index of size_t type and cast it to the type that setVal accepts while passing (and after I'm sure that the value is in the correct range)
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  3. #3
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by KIBO View Post
    For instance when you pass an array to a function and to be correct you better pass a size_t as the size too.

    Code:
    void func(OBJ results[3], size_t n) {	
      for (int i = 0; i < n; i++)  {
        if (results[i] != 0)
          results[i].SetVal(i);
      }
    }
    }
    Then if you loop through the array with an int you get the warning that you're mixing unsigned and signed types but if you change it to size_t and the SetVal expects an int then you get the warning there.

    How do you guys solve this?
    It really depends. Your code as written needs to do more error checking that it does, or have a documented set of preconditions (eg n <= 3) that is enforced by the caller.

    However, I'd do it something like this;
    Code:
    void func(OBJ results[3], size_t n)
    {	
      for (size_t i = 0; i < n && i < 3U; i++)   /* enforce range check */
      {
        if (results[i] != 0)
          results[i].SetVal((int)i);   /* we know i < 3 so the conversion is safe */
       }
    }
    There is also no mandatory punishment for using additional variables, and that's one way to avoid having to do a conversion. For example;
    Code:
    void func(OBJ results[3], size_t n)
    {
      size_t i;
      int  i_as_int;	
      for (i = 0, i_as_int = 0; i < n && i < 3U; i++, i_as_int++)
      {
        if (results[i] != 0)
          results[i].SetVal(i_as_int);
       }
    }
    }
    The only catch is that it's not possible to define variables of two distinct types within the for() construct, which is the reason I've moved the variable definitions before the loop. There is potentially a (very slight) overhead in this but, if the relationship between i and i_as_int is well defined (eg above: they're equal value, although different types) modern compilers will often optimise out one of the variables anyway.

    In C++, one other way is to overload the SetVal() member function so it accepts either int or a size_t. Of course, that forces one of the SetVal() functions to do a conversion, but at least it's localised.

  4. #4
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Am I mistaken if the following is simply enough?

    Code:
    void func(OBJ results[3], size_t n) {
      assert(n < 3);	
      for (size_t i = 0; i < n; i++)  {
        if (results[i] != 0)
          results[i].SetVal(i);
      }
    }
    Don't implicit casts between signed and unsigned happen all the time and you can do very little about it? Isn't the compiler more worried about the comparison of different types (even though here you know that there is no reason to be worried)?

    Another option might be to modify SetVal to accept size_t too (and change the type of the underlying variable) if, as it appears from this usage, you will only be setting it to positive values anyway.

    Basically, you can do complicated things like grumpy shows or cast everything, but the behavior of the program won't change a bit whether you just let compiler do implicit cast, cast explicitly or use more variables to "avoid casting" - if there's an overflow it will happen the same no matter what you do. (To be safe, wouldn't you need to check before any operation whether it will overflow, something which you won't need to do if the ranges are well known?) So the only objective might be to silence the compiler warnings (which is safe here since you know the limits of possible values)?
    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).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 8
    Last Post: 06-04-2009, 02:03 PM
  2. How to tell a type is signed or unsigned?
    By meili100 in forum C++ Programming
    Replies: 22
    Last Post: 05-08-2008, 08:21 PM
  3. Direct3D problem
    By cboard_member in forum Game Programming
    Replies: 10
    Last Post: 04-09-2006, 03:36 AM
  4. Please STICKY this- vital to MSVC 6 dev - BASETSD.h
    By VirtualAce in forum Game Programming
    Replies: 11
    Last Post: 03-15-2005, 09:22 AM
  5. build errors migrated from dx9b to dx9c sdk
    By reanimated in forum Game Programming
    Replies: 4
    Last Post: 12-17-2004, 07:35 AM