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.

When I learned the C++ language for the first time I learned that besides int, float etc, smaller or bigger versions of these data types existed within the language. For example I could call a variable x

int x;
or 
short int x;

The main difference being that short int takes 2 bytes of memory while int takes 4 bytes, and short int has a lesser value, but we could also call this to make it even smaller:

int x;
short int x;
unsigned short int x;

which is even more restrictive.

My question here is if it's a good practice to use separate data types according to what values your variable take within the program. Is it a good idea to always declare variables according to these data types?

share|improve this question
2  
are you aware of Flyweight design pattern? "an object that minimizes memory use by sharing as much data as possible with other similar objects; it is a way to use objects in large numbers when a simple repeated representation would use an unacceptable amount of memory..." –  gnat Apr 17 '12 at 7:44
    
@gnat, I've never heard of that. Thanks for the reference. –  Bugster Apr 17 '12 at 7:45
4  
With standard packing/alignment compiler settings, the variables will be aligned to 4 byte boundaries anyway, so there might not by any difference at all. –  nikie Apr 17 '12 at 8:36
21  
Classic case of premature optimization. –  scarfridge Apr 17 '12 at 9:05
    
@nikie - they might be aligned on a 4 byte boundary on an x86 processor but this is not true in general. MSP430 places char on any byte address and everything else on an even byte address. I think that AVR-32 and ARM Cortex-M are the same. –  Ian Apr 17 '12 at 14:13
show 1 more comment

6 Answers 6

up vote 26 down vote accepted

Most of the time the space cost is negligible and you shouldn't worry about it, however you should worry about the extra information you are giving by declaring a type. For example, if you:

unsigned int salary;

You are giving a useful piece of information to another developer: salary cannot be negative.

The difference between short, int, long is rarely going to cause space problems in your application. You are more likely to accidentally make the false assumption that a number will always fit in some datatype. It's probably safer to always use int unless you are 100% sure your numbers will always be very small. Even then, it is unlikely to save you any noticeable amount of space.

share|improve this answer
3  
Its true it is rarely going to cause problems these days, but if you are designing a library or a class that another developer will use, well that's another matter. Maybe they will need storage for a million of these objects, in which case the difference is large - 4MB compared to 2MB just for this one field. –  dodgy_coder Apr 17 '12 at 7:40
12  
Using unsigned in this case is a bad idea: not only the salary cannot be negative, but the difference between two salaries cannot be negative either. (In general, using unsigned for anything but bit-twiddling and having defined behavior on overflow is a bad idea.) –  zvrba Apr 17 '12 at 9:01
3  
@zvrba: The difference between two salaries is not itself a salary and so it is legitimate to use a different type that is signed. –  JeremyP Apr 17 '12 at 16:03
7  
@JeremyP Yes but if you're using C (and it looks like this is true in C++ too), unsigned integer subtraction results in an unsigned int, which cannot be negative. It might turn into the right value if you cast it to a signed int, but the result of the computation is an unsigned int. See also this answer for more signed/unsigned computation weirdness - which is why you should never use unsigned variables unless you're really twiddling bits. –  Tacroy Apr 17 '12 at 16:15
2  
@JeremyP It forces you to write ugly code like (int)salary1 - salary2. If you have some invariants to preserve, encapsulate the data into a class. Though: why isn't the difference a salary? Addition and subtraction preserve physical quantities (e.g., the difference of velocities has the same units [m/s]), so what makes salary special? –  zvrba Apr 17 '12 at 16:31
show 7 more comments

The OP said nothing about the type of system they are writing programs for, but I assume the OP was thinking of a typical PC with GB's of memory since C++ is mentioned. As one of the comments says, even with that kind of memory, if you have several million items of one type -- such as an array -- then the size of the variable can make a difference.

If you get into the world of embedded systems -- which is not really outside the scope of the question, since the OP doesn't limit it to PCs -- then the size of data types very much matters. I just finished a quick project on a 8-bit microcontroller which has only 8K words of program memory and 368 bytes of RAM. There, obviously every byte counts. One never uses a variable bigger than they need (both from a space standpoint, and code size -- 8-bit processors use a lot of instructions to manipulate 16 and 32-bit data). Why use a CPU with such limited resources? In large quantities, they can cost as little as a quarter.

I'm currently doing another embedded project with a 32-bit MIPS-based microcontroller which has 512K bytes of flash and 128K bytes of RAM (and costs around $6 in quantity). As with a PC, the "natural" data size is 32-bits. Now it becomes more efficient, code-wise, to use ints for most variables instead of chars or shorts. But once again, any type of array or structure must be considered whether smaller data types are warranted. Unlike compilers for larger systems, it is more likely variables in a structure will be packed on an embedded system. I take care to always try to put all 32-bit variables first, then 16-bit, then 8-bit to avoid any "holes".

share|improve this answer
4  
+1 for the fact that different rules apply to embedded systems. The fact that C++ is mentioned does not mean that the target is a PC. One of my recent projects was written in C++ on a processor with 32k of RAM and 256K of Flash. –  Ian Apr 17 '12 at 14:03
add comment

Depending on how the specific operating system works, you generally expect the memory to be allocated unoptimized such that when you call for a byte, or a word or some other small data type to be allocated, the value occupies an entire register all of it's very own. How your compiler or interpreter works to interpret this however is something else, so if you were to compile a program in C# for instance, the value might physically occupy a register for itself, however the value will be boundary checked to ensure you don't try to store a value that will exceed the bounds of the intended datatype.

Performance-wise, and if you are really pedantic about such things, it's likely faster to simply use the datatype that most closely matches the target register size, but then you miss out on all of that lovely syntactic sugar that makes working with variables so easy.

How does this help you? Well, it's really up to you to decide what sort of situation you are coding for. For nearly every program I have ever written, it's enough to simply trust your compiler to optimize things and to use the datatype that is most useful to you. If you need high precision, use the larger floating point data types. If working with only positive values, you can probably use an unsigned integer, but for the most part, simply using the int datatype is enough.

If however you have some very strict data requirements, such as writing a communications protocol, or some sort of encryption algorithm, then using range-checked datatypes can come in very handy, particularly if you are trying to avoid problems relating to data overruns/underruns, or invalid data values.

The only other reason I can think of off the top of my head to use specific datatypes is when you are trying to communicate intent within your code. If you use a shortint for example, you are telling other developers that you are allowing positive and negative numbers within a very small value range.

share|improve this answer
add comment

The answer depends on your system. Generally, here are the advantages and disadvantages of using smaller types:

Advantages

  • Smaller types use less memory on most systems.
  • Smaller types gives faster calculations on some systems. Particularly true for float vs double on many systems. And smaller int types also give significantly faster code on 8- or 16-bit CPUs.

Disadvantages

  • Many CPUs have alignment requirements. Some access aligned data faster than unaligned. Some must have the data aligned to even be able to access it. The larger integer types equal one aligned unit, so they are most likely not misaligned. This means that the compiler might be forced to put your smaller integers in larger ones. And if the smaller types are part of a larger struct, you may get various padding bytes silently inserted anywhere in the struct by the compiler, to fix alignment.
  • Dangerous implicit conversions. C and C++ have several obscure, dangerous rules for how variables are promoted to larger ones, implicitly without a typecast. There are two sets of implicit conversion rules entwined with each other, called the "integer promotion rules" and the "usual arithmetic conversions." Read more about them here. These rules are one of the most common causes for bugs in C and C++. You can avoid a whole lot of problems by simply using the same integer type all over the program.

My advise is to like this:

system                             int types

small/low level embedded system    stdint.h with smaller types
32-bit embedded system             stdint.h, stick to int32_t and uint32_t.
32-bit desktop system              Only use (unsigned) int and long long.
64-bit system                      Only use (unsigned) int and long long.

Alternatively, you can use the int_leastn_t or int_fastn_t from stdint.h, where the n is the number 8, 16, 32 or 64. int_leastn_t type means "I want this to be at least n bytes but I don't care if the compiler allocates it as a larger type to suit alignment".

int_fastn_t means "I want this to be n bytes long, but if it will make my code will run faster, the compiler should use a larger type than specified".

Generally, the various stdint.h types are much better practice than plain int etc, because they are portable. The intention with int was to not give it a specified width solely to make it portable. But in reality, it is hard to port because you never know how large it will be on a specific system.

share|improve this answer
add comment

As scarfridge commented, this is a

Classic case of premature optimization.

Trying to optimise for memory usage might impact other areas of performance, and the golden rules of optimisation are:

The First Rule of Program Optimisation: Don't do it.

The Second Rule of Program Optimisation (for experts only!): Don't do it yet."

— Michael A. Jackson

In order to know whether now is the time to optimise requires benchmarking and testing. You need to know where your code is being inefficient, so that you can target your optimisations.

In order to determine whether the optimised version of the code is actually better than the naive implementation at any given time, you need to benchmark them side-by-side with the same data.

Also, remember that just because a given implementation is more efficient on the current generation of CPU's, doesn't mean it will always be so. My answer to the question Is micro-optimisation important when coding? details an example from personal experience where an obsolete optimisation resulted in an order of magnitude slowdown.

On many processors, unaligned memory accesses are significantly more costly than aligned memory accesses. Packing a couple of shorts into your struct may just mean that your program has to perform pack/unpack operation every time you touch either value.

For this reason, modern compilers ignore your suggestions. As nikie comments:

With standard packing/alignment compiler settings, the variables will be aligned to 4 byte boundaries anyway, so there might not by any difference at all.

Second guess your compiler at your peril.

There is a place for such optimisations, when working with terabyte datasets or embedded micro-controllers, but for most of us, it isn't really a concern.

share|improve this answer
add comment

The main difference being that short int takes 2 bytes of memory while int takes 4 bytes, and short int has a lesser value, but we could also call this to make it even smaller:

This is incorrect. You can't make assumptions about how many bytes each type holds, other than char being one byte and at least 8 bits per byte, along with each type's size being greater than or equal to the previous.

The performance benefits are incredibly minuscule for stack variables - they'll likely be aligned/padded anyway.

Because of this, short and long have practically no use nowadays, and you're almost always better off using int.


Of course, there's also stdint.h which is perfectly fine to use when int doesn't cut it. If you're ever allocating huge arrays of integers/structs then an intX_t makes sense as you can be efficient and rely on the size of the type. This is not at all premature as you can save megabytes of memory.

share|improve this answer
1  
Actually, with the advent of 64 bit environments, long may be different to int. If your compiler is LP64, int is 32 bits and long is 64 bits and you'll find that ints may still be 4 byte aligned (my compiler does, for instance). –  JeremyP Apr 17 '12 at 16:11
1  
@JeremyP Yeah, did I say otherwise or something? –  Pubby Apr 17 '12 at 17:27
    
Your last sentence which claims short and long have practically no use. Long certainly does have a use, if only as the base type of int64_t –  JeremyP Apr 18 '12 at 9:10
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.