Signed integers have always bugged me. I've seen quite a bit of signed integer overuse in C#, but it is most egregious when dealing with C/C++ libraries that, for some reason, insist on using
for(int i = 0; i < 5; ++i)
. Why would you ever write that? i
cannot possibly be negative and for that matter shouldn't be negative, ever. Use for(unsigned int i = 0; i < 5; ++i)
, for crying out loud.
But really, that's not a fair example. You don't really lose anything using an integer for the i value there because its range isn't large enough. The places where this become stupid are things like using an integer for height and width, or returning a signed integer count. Why on earth would you want to return a negative count? If the count fails, return an unsigned -1, which is just the maximum possible value for your chosen unsigned integral type. Of course, certain people seem to think this is a bad idea because then you will return the largest positive number possible. What if they interpret that as a valid count and try to allocate 4 gigs of memory? Well gee, I don't know, what happens when you try to allocate -1 bytes of memory? In both cases, something is going to explode, and in both cases, its because the person using your code is an idiot. Neither way is more safe than the other. In fact, signed integers cause far more problems then they solve.
One of the most painfully obvious issues here is that virtually every single architecture in the world uses the two's complement representation of signed integers. When you are using two's complement on an 8-bit signed integer type (a
char
in C++), the largest positive value is 127, and the largest negative value is -128. That means a signed integer can represent a negative number so large it cannot be represented as a positive number. What happens when you do (char)abs(-128)
? It tries to return 128, which overflows back to... -128. This is the cause of a host of security problems, and what's hilarious is that a lot of people try to use this to fuel their argument that you should use C# or Java or Haskell or some other esoteric language that makes them feel smart. The fact is, any language with fixed size integers has this problem. That means C# has it, Java has it, most languages have it to some degree. This bug doesn't mean you should stop using C++, it means you need to stop using signed integers in places they don't belong. Observe the following code:
if (*p == '*') { ++p; total_width += abs (va_arg (ap, int)); }This is retarded. Why on earth are you interpreting an argument as a signed integer only to then immediately call
abs()
on it? So a brain damaged programmer can throw in negative values and not blow things up? If it can only possibly be valid when it is a positive number, interpret it as a unsigned int
. Even if someone tries putting in a negative number, they will serve only to make the total_width
abnormally large, instead of potentially putting in -128, causing abs()
to return -128 and creating a total_width
that is far too small, causing a buffer overflow and hacking into your program. And don't go declaring total_width
as a signed integer either, because that's just stupid. Using an unsigned integer here closes a potential security hole and makes it even harder for a dumb programmer to screw things up1.
I can only attribute the vast overuse of
int
to programmer laziness. unsigned int
is just too long to write. Of course, that's what typedef
's are for, so that isn't an excuse, so maybe they're worried a programmer won't understand how to put a -1 into an unsigned int
? Even if they didn't, you could still cast the int
to an unsigned int
to serve the same purpose and close the security hole. I am simply at a loss as to why I see int
's all over code that could never possibly be negative. If it could never possibly be negative, you are therefore assuming that it won't be negative, so it's a much better idea to just make it impossible for it to be negative instead of giving hackers 200 possible ways to break your program.
1 There's actually another error here in that
total_width
can overflow even when unsigned, and there is no check for that, but that's beyond the scope of this article.