djpetti
djpetti

Reputation: 191

What are some good guidelines for choosing the size of integer types?

I've been searching around a bit, and I haven't really come up with an answer for this.

When I'm programming on embedded devices with limited memory, I'm generally in the habit of using the smallest integral/floating point type that will do the job, for instance, if I know that a counter will always be between zero and 255, I'll declare it as a uint8_t.

However, in less memory-constrained environments, I'm used to just using int for everything, as per the Google C++ Styleguide. When I look at existing code, it often tends to be done this way.

To be clear, I get the rationale behind doing this, (Google explains it very well), but I'm not precisely clear on the rationale behind doing things the first way.

It seems to me that reducing the memory footprint of your program, even on a system where you don't care about memory usage, would be good for overall speed, since, logically, less overall data would mean more of it could fit in CPU cache.

Complicating matters, however, is the fact that compilers will automatically pad data and align it to boundaries such that it can be fetched in a single bus cycle. I guess, then, it comes down to whether or not compilers are smart enough to take, say, two 32-bit integers and stick them together in a single 64-bit block vs. individually padding each one to 64 bits.

I suppose whether or not the CPU itself could take advantage of this also depends on its exact internals, but the idea that optimizing memory size improves performance, particularly on newer processors, is evidenced in the fact that the Linux kernel relied for awhile on gcc's -0s option for an overall performance boost.

So I guess that my question is why the Google method seems to be so much more prevalent in actual code. Is there a hidden cost here that I'm missing?

Upvotes: 6

Views: 367

Answers (4)

Klaus
Klaus

Reputation: 25603

Nice discussion! But I wonder why nobody speaks about cpu register size, memory bus architecture, cpu architecture and so on. Saying "int is best" is not a general at all. If you have small embedded systems like 8 bit avr, int is a very bad choice for a counter running from 0 .. 255.

And using int on ARM where you maybe have a 16 bit bus interface can also be a very bad idea if you really only need 16 bits or less.

As for all optimizations: Look in the code the compiler produces, measure how long actions really take and look for memory consumption on heap/stack if it is necessary. It makes no sense to hand craft unmaintainable code to save 8 bits somewhere if your hardware still have MBytes left.

Using tools like valgrind and the profiling supported by the target/compiler give much more ideas as any theoretical discussions here.

There is no general "best integer type"! It depends always on CPU architecture, memory bus, caches and a some more.

Upvotes: 0

Ralph Tandetzky
Ralph Tandetzky

Reputation: 23610

From my experience 90% of all code in a bigger project does not need particular optimization, since 95% of all memory consumption and of all execution time is spend in less than 10% of the code you write. In the rest of the code, try to emphasize simplicity and maintainability. Mostly, that means using ints or size_t as integer types. Usually, there is not need to optimize the size of local variables, but it can make sense, if you have a lot of instances of a type in a large array. Item 6 in the excellent book C++ Coding Standards: 101 Rules, Guidelines and Best Practices (C++ In-Depth) by Herb Sutter and Andrei Alexandrescu says:

"Correctness, simplicity, and clarity come first."

Most importantly, understand where these less than 10% of code are, that really need optimization. Otherwise, keep interfaces simple and uniform.

Upvotes: 0

MSalters
MSalters

Reputation: 179799

"embedded devices ... counter between zero and 255, I'll declare it as a uint8_t"

That might be counterproductive. Especially on embedded systems, 8 bit fetches might be slower. Besides, a counter is likely in a register, and there's no benefit in using half a register.

The chief reason to use uint8_t is when you have a contiguous set of them. Could be an array, but also adjacent members in a class.

As the comments already note, -Os is unrelated - its benefit is that with smaller code, the memory bus has more bandwidth left for data.

Upvotes: 2

Peter
Peter

Reputation: 36597

The usual reasons that the "google method" is commonly used is because int is often good enough, and it is typically the first option taught in beginner's material. It also takes more effort (man hours, etc) to optimise a nontrivial code for "limited memory" - effort which is pointless if not actually needed.

If the "actual code" is written for portability, then int is a good default choice.

Whether written for portability or not, a lot of programs are only ever run on hosts with sufficient memory resources and with an int type that can represent the required range of values. This means it is not necessary to worry about memory usage (e.g. optimising size of variables based on the specific range of values they need to support) and the program just works.

Programming for "limited memory" is certainly common, but not typically why most code is written. Quite a few modern embedded systems have more than enough memory and other resources, so the techniques are not always needed for them.

A lot of code written for what you call "limited memory" also does not actually need to be. There is a point, as programmers learn more, that a significant number start indulging in premature optimisation - worrying about performance or memory usage, even when there is no demonstrated need for them to do so. While there is certainly a significant body of code written for "limited memory" because of a genuine need, there is a lot more such code written due to premature optimisation.

Upvotes: 3

Related Questions