#pragma pack
is accepted by many C/C++ compilers as the de facto standard grammar to handle alignment of variables.However there is an old bug in GCC, reported many times, the first of which was in 2002, still not fixed now.
#include <cstdio> using namespace std; #pragma pack(1) template <typename T> struct A { char a; int b; }; A<int> x; #pragma pack(2) A<char> y; #pragma pack(4) A<short> z; int main() { printf ("%d %d %d\n", sizeof x,sizeof y,sizeof z); return 0; }
This gives
5 6 8
instead of 5 5 5
as we may expect. (VC++ and ICC both give the more reasonable 5 5 5
.)This example is not very bad. Even worse is, that this bug can damage programs that use STL. Here is an example:
a.cpp
:#include <cstdio> #include <map> using namespace std; #pragma pack(1) void foo (const map<short,const char*> &x) { for (map<short,const char*>::const_iterator it=x.begin(); it!=x.end(); ++it) printf ("%d %s\n", it->first, it->second); }
b.cpp
:#include <map> using namespace std; void foo (const map<short,const char *> &); int main() { map<short, const char *> x; x[0] = "Hello"; x[1] = "World"; foo (x); }
Compile
a.cpp
and b.cpp
separately and link them together. This program segfaults if compiled with GCC, but works well with ICC or VC++.In conclusion, for better portability and/or reliability, never use
#pragma pack
unless absolutely necessary. If really unavoidable, always push
and pop
immediately before and after the structure definition. (If the program is intended to be compiled by GCC/ICC only, it is better to use the more reliable GCC-specific __attribute__((__packed__))
.)PS. It seems Sun CC (shipped with Solaris) also has this bug. It fails for the first example here, but for the second it works well. I don't know how manages to align
pair<short,const char *>
correctly...
No comments:
Post a Comment