On 2008-06-07 12:43, Juha Nieminen wrote:
I was once taught that if some integral value can never have negative
values, it's a good style to use an 'unsigned' type for that: It's
informative, self-documenting, and you are not wasting half of the value
range for values which you will never be using.
I agreed with this, and started to always use 'unsigned' whenever
negative values wouldn't make any sense. I did this for years.
However, I slowly changed my mind: Doing this often causes more
problems than it's worth. A good example:
If you have an image class, its width and height properties can
*never* get negative values. They will always be positive. So it makes
sense to use 'unsigned' for the width and height, doesn't it? What
problems could that ever create?
Well, assume that you are drawing images on screen, by pixel
coordinates, and these images can be partially (or completely) outside
the screen. For example, the left edge coordinate of the image to be
drawn might have a negative x value (for example drawing a 100x100 image
at coordinates <-20, 50>). Since the coordinates are signed and the
dimensions of the image are unsigned, this may cause signed-unsigned
mixup. For example this:
if(x - width/2 < 1) ...
where 'x' is a signed integer, gives *different* results depending on
whether 'width' is signed or unsigned, with certain values of those
variables (for example x=2 and width=10).
Wow, that was certainly an eye-opener. I had assumed that in this case
both values would be promoted to some larger type (signed long) which
could accurately represent both values (the signed and the unsigned int)
but apparently not.
This is a defect in the standard in my opinion since it allows the
correct action to be taken for types smaller than int:
#include <iostream>
int main()
{
unsigned short width = 10;
short x = 2;
std::cout << (x - width);
return 0;
}