Wednesday 14 December 2016

Data allignment in C

I am fan of travelling. But just not as a hobby or an activity I'd like to take, instead as an analogy to understand and hence communicate some efficiency concerns in computers. I am going to do this again.
When one has to travel and that to frequently then what you'd expect the number of items of their luggage to be? As less as possible right? A traveller (at least a wise one) would want to pack things in (say) one bag so that carrying stuff isn't as prominent a pain as it otherwise would be. Now assume that on a single trip, one is allowed to take only one bag. Considering the trip costs money and more importantly, time, one would want to take this trip once only. Packing your stuff in two separate bags would be stupid as then you'd have to travel twice in order to complete the transfer.
The idea is to keep things packed in such a manner that one would not require more bags to carry them. You want only one bag or at the most, a number of bags that you can carry at once.
A program travels too, more frequently then any human in any imaginable circumstance. And while travelling, a program also has to carry stuff from memory to the CPU, or back. As such you'd want your program to carry the whole data belonging to the same variable once, in one data cycle. A 64 bit CPU can carry 64 bits at once. So if you have 65 bits of data in memory then that will force your CPU to take two trips in order to fetch this data entirely. But this is okay as no altercation would make this transaction more efficient, CPU can only carry 64 bits in parallel.
Another interesting peculiar feature of CPUs is their habit of considering only those chunks of memory that start from an address which is a multiple of the word size. So if the word size was X then the CPU would only fetch memory chunks starting from 0, X, 2X, 3X, ... This means that if some thing is placed in such a way in memory that it is not wholly a part of any of these chunks, then the CPU will have to make two trips in order to fetch it and then will have to perform some bit shifting in order to restore the proper value of the thing being fetched as well.
Data types in C (with exception of char) have even bit sizes. Their size is always a multiple of 2. More importantly, except for chars, all other primitive data types in C are either a multiple or a factor of the word size on most architectures. Most modern architectures have a word size which is a multiple of 4, so this means that almost all primitive data types in C should also be a multiple or a factor of 4 bytes in size. You won't see a data type in C that is primitive and has a size of 6 bytes or 10 bytes or 14 bytes with the exception of long double. The size will be either 2, 4 or any multiple of 4.
When a compiler has to store a variable of a particular type, the starting address available to store the variable can be anything (depending what and how things were packed before). If the compiler just went ahead and stored the variable exactly at the address that was available then that could lead to some inefficiencies in getting that variable back from memory. For example consider that the variable size is 4 and the starting address available to store the variable is 18, then if the storage was done simply, the variable will reside in memory from the address 18 to 22. This will lead to the same problem described in the earlier paragraphs. Since the variable will be residing in two separate memory chunks (that start from a multiple of 4 and are 4 bits in size), the CPU will have to take two trips in order to fetch it completely and then will have to perform some bit shifting on the partial values of both the chunks in order to retrieve the proper value of the variable. Now ask yourself, wouldn't it be nicer if this variable was stored at address 20 to 24 even if that meant leaving two empty bits at 18 and 19? Of course it would, as now the CPU could simple fetch the variable in one go and would not require any manipulation of bits in order to get the proper value of the variable.
For this reason the C language enforces some rules that determine how the variables of various sizes are to be stored. The general rule is that if a variable is of size S then it must be stored at an address that is a multiple of S as well. Since the the size of variables (as mentioned above) align (mostly) with the word size of machines, this enforcement ensures that no variable has to be split between two memory words.

No comments:

Post a Comment