Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I use unsigned ints everywhere, and I'm not sure if I should. This can be from database primary key id columns to counters, etc. If a number should never be negative, then I will always used an unsigned int.

However I notice from other's code that no one else seems to do this. Is there something crucial that I'm overlooking?

Edit: Since this question I've also noticed that in C, returning negative values for errors is commonplace rather than throwing exceptions as in C++.

share|improve this question
16  
Just watch out for for(unsigned int n = 10; n >= 0; n --) (loops infinitely) –  Chris Burt-Brown Aug 1 '11 at 10:55
1  
In C and C++, unsigned ints have precisely defined overflow behaviour (modulo 2^n). Signed ints don't. Optimisers increasingly exploit that undefined overflow behaviour, leading to surprising results in some cases. –  Steve314 Aug 1 '11 at 17:34
2  
Good question! I too was once tempted to use uints t restrict range but found that the risk/inconvenience did outweigh any benefit/convenience. Most libraries, as you said, accept regular ints where a uint would do. This makes it hard to work with, but also begs the question: is it worth it? In practice (assuming that you do not go about things in a dumb way), you will rarely have a value of -218 come in where a positive one is expected. That -218 must have come from somewhere, right? and you can trace its origin. Happens rarely. Do utilize assertions, exceptions, code contracts to assist you. –  Job Aug 13 '11 at 14:33
    
@William Ting: If this is about C/C++ only, you should add the appropriate tags to your question. –  CesarGon Aug 13 '11 at 16:15
1  
@Chris: How significant is the infinite loop problem in reality? I mean, if it does make its way into release, then the code obviously wasn't tested. Even when you need some hours to debug it the first time you make this error, the second time you should know what to look for first when your code doesn't stop looping. –  Secure Aug 14 '11 at 14:14

10 Answers 10

up vote 16 down vote accepted

Is there something crucial that I'm overlooking?

When calculations involve both signed and unsigned types as well as different sizes, the rules for type promotion can be complex and lead to unexpected behaviour.

I believe this is the main reason why Java omitted unsigned int types.

share|improve this answer
1  
Another solution would be to require you to manually cast your numbers as appropriate. This is what Go seems to do (I've only played around with it a tiny bit though), and I like it more than Java's approach. –  Tikhon Jelvis Jul 14 '12 at 0:02
1  
That was a good reason for Java not to include 64-bit unsigned type, and maybe a decent reason not to include a 32-bit unsigned type [though the semantics of adding signed and unsigned 32-bit values wouldn't be hard--such an operation should simply yield a 64-bit signed result]. Unsigned types smaller than int would pose no such difficulty, however (since any computations will promote to int); I have nothing good to say about the lack of an unsigned-byte type. –  supercat Dec 3 at 22:36

You should care about this when you're dealing with an integer that might actually approach or exceed the limits of a signed int. Since the positive maximum of a 32 bit integer is 2,147,483,647 then you should use an unsigned int if you know it will a) never be negative and b) might reach 2,147,483,648. In most cases, including database keys and counters, I will never even approach these kinds of numbers so I don't bother concerning myself with worrying whether the sign bit is used for a numeric value or to indicate the sign.

I would say: use int unless you know you need an unsigned int.

share|improve this answer
    
When working with values that can reach the maximum values, you should start to check the operations for integer overflows, regardless of the sign. These checks are usually easier for unsigned types, because most operations have well defined results without undefined and implementation defined behaviour. –  Secure Jul 15 '12 at 9:21

Encoding range information into types is A Good Thing. It enforces using reasonable numbers at compile time.

Many architectures seem to have specialized instructions for dealing with int -> float conversions. The conversion from unsigned can be slower (a tiny bit).

share|improve this answer

I use unsigned int in C++ for array indices, mostly, and for any counter which starts from 0. I think it is good to say explicitly "this variable cannot be negative".

share|improve this answer
7  
You should probably be using size_t for this in c++ –  JohnB Aug 1 '11 at 13:10
1  
I know, I just can't be bothered to. –  quant_dev Aug 1 '11 at 13:14

I think that Michael has a valid point, but IMO the reason why everybody uses int all the time (especially in for int i = 0; i < max, i++) is that we learned it that way. When every single example in a how to learn programming book uses int in a for loop, very few will ever question that practice.

The other reason is that int is 25% shorter than uint, and we are all lazy... ;-)

share|improve this answer
    
I agree with the educational issue. Most people seem never to question what they read: If it's in a book, it cannot be wrong, right ? –  Matthieu M. Aug 14 '11 at 13:14

For me types are much about communication. By using explicitly an unsigned int you tell me that signed values are not valid values. This allows me to add some information when reading your code in addition to the variable name. Ideally I a non anonymous type would tell me more, but it gives me more information than if you had used ints everywhere.

Unfortunately not everybody is very conscious about what their code communicates, and that is probably the reason you see ints everywhere even though the values are at least unsigned.

share|improve this answer
2  
But I might want to restrict my values for a month to 1 through 12 only. Do I use another type for it? What about a month? Some languages actually allow restricting values like that. Others, such as .Net/C# provide Code Contracts. Sure, non-negative integers occur rather frequently, but most languages that support this type do not support further restrictions. So, should one use a mix of uints and error checking, or just do everything through error checking? Most libraries do not ask for uint where it would make sense to use one, hence using one and casting can be inconvenient. –  Job Aug 15 '11 at 3:17
    
@Job I would say you should use some kind of compiler/interpreter enforced restriction on your months. It may give you some boilerplate to set up, but for the future you have an enforced restriction that prevents error and communicates much clearer what you are expecting. Preventing errors and easing communication are much more important than inconvenience while implementing. –  daramarak Apr 12 '13 at 6:31

I'm inclined to agree with Joel Etherton's reasoning, but come to the opposite conclusion. The way I see it, even if you know that numbers are unlikely to ever approach the limits of a signed type, if you know that negative numbers won't happen, then there is very little reason to use the signed variant of a type.

For the same reason why I have, in a few select instances, used BIGINT (64 bit integer) rather than INTEGER (32-bit integer) in SQL Server tables. The probability that the data would hit the 32-bit limit within any reasonable amount of time is miniscule, but if it happens, the consequences in some situations could be quite devastating. Just be sure to map types between languages properly, or you are going to end up with interesting weirdness really far down the road...

That said, for some things, such as database primary key values, signed or unsigned really doesn't matter, because unless you are manually repairing broken data or something along those lines, you aren't ever dealing with the value directly; it's an identifier, nothing more. In those cases, consistency is probably more important than the exact choice of signedness. Otherwise, you end up with some foreign key columns that are signed and others that are unsigned, with no apparent pattern to it - or that interesting weirdness again.

share|improve this answer
    
If you are working with data extracted from an SAP system, I strongly recommend BIGINT for ID fields (like CustomerNumber, ArticleNumber etc). As long as nobody uses alphanumeric strings as IDs, that is... sigh –  Treb Aug 18 '11 at 19:45

It's a tradeoff between simplicity and reliability. The more bugs that can be caught at compile time, the more reliable the software. Different people and organizations are on different points along that spectrum.

If you ever do any high-reliability programming in Ada, you even use different types for variables like distance in feet vs. distance in meters, and the compiler flags it if you accidentally assign one to the other. That's perfect for programming a guided missile, but overkill (pun intended) if you're validating a web form. There's not necessarily anything wrong with either way as long as it fits the requirements.

share|improve this answer

Mixing signed and unsigned types can get you into a world of pain. And you can't use all unsigned types because you will encounter things that either have a valid range that includes negative numbers or need a value to indicate an error and -1 is most natural. So the net result is that many programmers use all signed integers types.

share|improve this answer
1  
@DeadMG - C doesn't support exceptions, remember? Also, lots of people still interact with the C library (which doesn't use exceptions), and there are a lots of times even in C++ when exceptions simply aren't appropriate. –  Michael Kohne Jul 14 '12 at 23:47
1  
Maybe it's a better practice to not mix valid values with error indication in the same variable and to use separate variables for this. Granted, the C standard library doesn't set a good example here. –  Secure Jul 15 '12 at 9:25

I would recommend that outside space-constrained data-storage and data-interchange contexts, one should generally use signed types. In most cases where a 32-bit signed integer would too small but a 32-bit unsigned value would suffice for today, it won't be long before the 32-bit unsigned value isn't big enough either.

The primary times one should use unsigned types are when one is either assembling multiple values into a larger one (e.g. converting four bytes to a 32-bit number) or decomposing larger values into smaller ones (e.g. storing a 32-bit number as four bytes), or when one has a quantity which is expected to "roll over" periodically and one needs to deal with it (think of a residential utility meter; most of them have enough digits to ensure that they won't possibly roll over between readings if they're read three times a year, but not enough to ensure they won't roll over within the useful life of the meter). Unsigned types often have enough 'weirdness' that they should only be used in cases where their semantics are necessary.

share|improve this answer
    
"I would recommend [...] generally use signed types." Hm, you forgot to mention the advantages of signed types and only gave a list of when to use unsigned types. "weirdness"? While most unsigned operations have well defined behaviour and results, you enter undefined and implementation defined behaviour when using signed types (overflow, bit shift, ...). You have a strange definition of "weirdness" here. –  Secure Jul 15 '12 at 9:15
1  
@Secure: The "weirdness" to which I refer has to do with the semantics of comparison operators, especially in operations which involve mixed signed and unsigned types. You are correct that the behavior of signed types is undefined when using values large enough to overflow, but the behavior of unsigned types can be surprising even when dealing with relatively small numbers. For example, (-3)+(1u) is greater than -1. Also, some normal mathematical associative relations that would apply to numbers don't apply to unsigned. For example, (a-b)>c does not imply (a-c)>b. –  supercat Jul 16 '12 at 14:34
1  
@Secure: While it's true that one can't always rely on such associative behavior with "large" signed numbers either, the behaviors do work as expected when dealing with numbers that are "small" relative to the domain of signed integers. By contrast, the above mentioned non-association is problematic with unsigned values "2 3 1". Incidentally, the fact that signed behaviors have undefined behavior when used out of bounds can allow for improved code generation on some platforms when using values smaller than the native word size. –  supercat Jul 16 '12 at 14:37
    
Had these comments been in your answer in the first place, instead of a recommendation and "name-calling" without giving any reasons, I wouldn't have commented it. ;) Though I still not agree with "weirdness" here, it's simply the definition of the type. Use the right tool for the given job, and know the tool, of course. Unsigned types are the wrong tool when you need +/- relations. There is a reason why size_t is unsigned and ptrdiff_t is signed. –  Secure Jul 16 '12 at 20:35
    
@Secure: When working with things that are supposed to represent numbers, I would suggest that one should use types which behave like numbers whenever practical. The wrapping behavior of unsigned types is useful in situations where such behavior is required, but I would say that an unsigned type behaves like an abstract algebraic field with a modulus-based equivalence relation, rather than that of a number. –  supercat Jul 16 '12 at 20:55

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.