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.

Do most application developers use signed integers in places where they really mean to use unsigned integers? I do it all the time, so do my co-workers. I haven't seen a lot of other extensive codebases (other than the Delphi VCL) and examples on the internet usually use integer. Whereas the VCL developers use their own data types (which would be the most non-lazy way to go about declaring variables).

Something seems a little dreadful about code like this

TStuffRec = record
   recordID : Integer;
   thingID : Integer;
   otherThingID : Integer;
end;

when it could be written as

TStuffRec = record
   recordID : Cardinal;
   thingID : Cardinal;
   otherThingID : Cardinal;
end;

Functionally, these records almost always work the same (and hopefully will continue to work the same even in 64-bit Delphi). But very large numbers will have conversion issues.

But there are drawbacks to using unsigned ints too. Mainly stemming from how annoying it is to mix the two.

The real question is, is this a thing that actually gets thought about or included in best practices? Is it usually just up to the developer?

share|improve this question
5  
Peter, are you looking for Delphi-specific answers only? –  Anna Lear Jul 25 '11 at 20:51
2  
@Anna Understanding how Delphi datatypes work would make for a most excellent answer. I'm reasonably sure that C programmers could comprehend and answer this question though. –  Peter Turner Jul 25 '11 at 20:58
add comment

3 Answers

up vote 8 down vote accepted

One reason why I don't use unsigned integer types all that much in Delphi is that they can create problems when mixed with signed integers. Here's one that bit me once:

for i := 0 to List.Count - 1 do
  //do something here

I had i declared as an unsigned integer, (after all, it's an index into a list that starts at 0, it never has to be negative, right?), but when List.Count was 0, it would not short-circuit the loop as expected because 0 - 1 evaluates to a really high positive number. Oops!

Between the potential safety problems inherent in mixing signed and unsigned integers, and the range issues, (if you're going to need positive numbers larger than high(signed whatever), it's quite likely that you'll also end up needing positive numbers larger than high(unsigned whatever) too, so moving up to the next larger size instead of switching from signed to unsigned of the same size is usually the correct action,) I really haven't found too many uses for unsigned integers when representing most data.

share|improve this answer
2  
Somewhat related, one of the major risks of using a data type that's potentially smaller than necessary (as opposed to just unsigned vs. signed) is that if the exit condition is larger than you planned for, you can actually end up with an infinite loop as the counter overflows again and again. It sounds stupid in hindsight, but I once wrote a program that was supposed to loop through every possible byte value, and it took about 15 minutes to finally convince myself that it was not possible to do with a byte counter. –  Aaronaught Jul 25 '11 at 23:40
    
@Aaronaught: Not in Delphi. (At least not unless you do something stupid like disabling the built-in overflow checking.) You'll end up with an exception when the counter overflows, instead of an infinite loop. It's still a bug, but it's a lot easier to track down. –  Mason Wheeler Jul 25 '11 at 23:47
    
If you say so. I always disabled overflow checking in Delphi; after getting endlessly bombarded with false positives from things like hash codes and checksums, I just gave up on that "feature" entirely. But I suppose you're right, it would have caught that specific error. –  Aaronaught Jul 25 '11 at 23:53
    
@Aaronaught: Well yeah, you'd want to disable it for stuff like hash codes and checksums that are specifically designed to overflow and wrap around. But for general-purpose calculations that are not designed to overflow and wrap around, it's an important safety feature and turning it off is kinda like driving without a seat belt. –  Mason Wheeler Jul 26 '11 at 0:12
    
Perhaps you've forgotten, but the overflow checking and compiler directives were incredibly buggy in older versions of Delphi. I can vividly remember tearing my hair out on multiple occasions after seeing the debugger stop directly in the middle of a {$O-}/{$O+} block to cheerfully report an overflow. After a while I couldn't take it anymore and just disabled it globally. Again, yeah, it would have caught this issue, but I still don't think it's worth the number of false positives. To each his own, of course! –  Aaronaught Jul 29 '11 at 2:41
add comment

To be honest I tend to use Integers by habit. I got used to fact that they offer ranges big enough for most situations and allow negative values (such as -1). Indeed, a lot of times using bytes/word/shortint would be more appropriate. Now thinking about it I can focus on these spots:

  • Perspective. Tilemap size is limited to 192x192 tiles, so I could use byte for addressing tiles and loops. But if map size to be increased I will have to go through every use and replace it with e.g. word. When I need to allow off-map objects I would have to go again to change to smallint.

  • Loops. It is often I write a loop "from i:=0 to Count-1", what happens if "i" is byte and Count=0 is that loop runs from 0 to 255. Not that I would want it.

  • Uniforming. It's easier to remember and to apply "var i:integer;" than to stop in each case and think "Hm.. here we are dealing with 0..120 range.. byte.. no, wait, we might need -1 for uninitialized.. shortint.. wait.. what if 128 is not enough.. Arrgh!" or "Why is it smallint in this place, not a shortint?"

  • Combining. When I need to combine two or more classes together they might be using different data types for their purposes, using broader types allows to skip unnecessary conversions.

  • -1. Even when values are on 0..n-1 range I often need to set "no value/unknown/uninitialized/empty" value, which is by common practice -1.

Using Integers allows to skip all these issues, forget about low-level optimization where it is not needed, go higher level and focus on more real problems.

P.S. When do I use other types?

  • Counters, they are never negative and are read-only outside of their class.
  • Performance/Memory reasons, force to use shorter data types in certain places.
share|improve this answer
add comment

The best practice is to use a data type that fits the needs for the data being used (expected data).

C# examples: If I only needed to support 0 to 255, I would use a byte.

If I needed to support 1,000,000 negative and positive, then int.

Bigger than 4.2 billion, then use a long.

By choosing the correct type, the program will use the optimal amount of memory as well as different types use different amounts of memory.

Here is a C# int reference from MSDN.

int 
 -2,147,483,648 to 2,147,483,647
 Signed 32-bit integer

uint 
 0 to 4,294,967,295
 Unsigned 32-bit integer

long 
 -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
 Signed 64-bit integer

ulong 
 0 to 18,446,744,073,709,551,615
 Unsigned 64-bit integer
share|improve this answer
    
In C# (or .net in general) would long and ulong become 128 bits on a 128-bit machine? Because in Delphi, the Integer datatype is 32 bits on a 32-bit machine and apparently will be 64 bits on a 64-bit machine. –  Peter Turner Jul 25 '11 at 21:01
1  
@Peter Turner: No, in C# int is just a shorthand for System.Int32, no matter what machine the code runs on. –  nikie Jul 25 '11 at 21:07
    
@nikie, is it just like type int System.Int32 or something to that effect? Could it be changed that easily in a future version of the framework? –  Peter Turner Jul 25 '11 at 21:12
    
@Peter Turner/nikie (sizeof(int).ToString()); ==> Returns 4 (sizeof(Int64).ToString()); ==> Returns 8 On my 64bit Windows OS. As nikie, stats, an int is really just and Int32. –  Jon Raynor Jul 25 '11 at 21:14
1  
One thing to note there is that not all types are compliant with the Common Language Specification. uint is one of such non-compliant types which means it should not be used in publicly exposed API to avoid breaking the ability to use that API in .NET languages other than the one the library is written in. This is also why the .NET framework API itself is using int where uint would do. –  Anna Lear Jul 26 '11 at 1:04
add comment

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.