Change of type alignment and the consequences

29.04.2009 Andrey Karpov

When porting software one of the task a developer faces is to change types' sizes and rules of their alignments. Not so long ago we provided support of the diagnosing rule allowing you to detect data structures which use memory on 64-bit inefficiently in Viva64 analyzer. But there is still some research work to be carried out in this field and I look through the messages concerning this topic in forums with attention.

This time my attention was attracted by a message in RSDN [1] running as follows:

Today I have faced a problem in Linux. There is a data structure consisting of several fields: 64-bit double, 8 unsigned char and one 32-bit int. Altogether it is 20 bytes (8 + 8*1 + 4). On 32-bit systems sizeof is 20 bytes and everything is OK. But on the 64-bit Linux sizeof returns 24 bytes. That is, an alignment at the 64-bit border takes place.

After that the author dwells upon data compatibility and asks for advice how to pack data in the structure. But at the moment we are not interested in this. What we are interested in is that there is a new type of errors which can occur when porting applications on a 64-bit system.

It is clear and common that when sizes of fields in a structure change, the size of the structure itself changes too because of this. But this is a different case. The size of the fields remains the same but the size of the structure will change too due to different alignment rules. This behavior can lead to various errors, for example, incompatibility of the formats of the data being saved.

Linux systems are not supported by Viva64 yet, but I decided to find out if such an error can occur in Windows systems. For this purpose I took an example of the code printing types' sizes and alignment from the article "C++ data alignment and portability" [2]. I've modified it a bit for Visual Studio and got this program:

#include <iostream>
using namespace std;
template <typename T>
void print (char const* name)
{
  cerr << name
       << " sizeof = " << sizeof (T)
       << " alignof = " << __alignof (T)
       << endl;
}
int _tmain(int, _TCHAR *[])
{
  print<bool>        ("bool          ");
  print<wchar_t>     ("wchar_t       ");
  print<short>       ("short int     ");
  print<int>         ("int           ");
  print<long>        ("long int      ");
  print<long long>   ("long long int ");
  print<float>       ("float         ");
  print<double>      ("double        ");
  print<long double> ("long double   ");
  print<void*>       ("void*         ");
}

I compared the data I'd got with the data described in the article "C++ data alignment and portability" for GNU/Linux systems and now give them in Table 1.

Table 1. Types' sizes and alignment.

Table 1. Types' sizes and alignment.

Let's study this table. Pay attention to the marked cells relating to long int and double. These types' sizes don't depend on the architecture's size and therefore don't change. Both on 32-bit and 64-bit systems their size is 8 byte. But alignment is different for 32-bit and 64-bit systems. It can cause change of the structure's size. When we implement Viva64 for Linux we'll take into consideration the possible errors relating to this.

In Windows systems, there are no such problems with alignment change. Pay attention that alignment of all the types doesn't change or changes together with the type's size. That is good - Windows developers have one potential problem off.

References