1:gcc中支持但不推荐使用的指令
#pragma pack() :取消内存对齐访问
#pragma pack(n) (n=1/2/4/8):按n字节对齐
#pragma pack(2)
struct mystruct1
{
int a;
char b;
short c;
}
struct mystruct2
{
int a;;
double b;
short c;
}
#pragma pack()
  以上这部分内容是按2字节对齐了。
  分析:
  (1)#pragma是用来指挥编译器,或者说设置编译器的对齐方式的。编译器的默认对齐方式是4,但是有时候我不希望对齐方式是4,而希望是别的(譬如希望1字节对齐,也可能希望是8,甚至可能希望128字节对齐)。
  (2)常用的设置编译器编译器对齐命令有2种:第一种是#pragma pack(),这种是设置编译器1字节对齐(有些人喜欢讲:设置编译器不对齐访问,还有些讲:取消编译器对齐访问);第二种是#pragma pack(4),这个括号中的数字表示我们希望多少字节对齐。
  (3)我们需要#prgama pack(n)开头,以#pragma pack()结尾,定义一个区间,这个区间内的对齐参数是n。
  (4)#prgma pack的方式在很多C环境下都是支持的,但是gcc虽然也可以不过不建议使用。
  2:gcc推荐的指令
  __attribute__((packed)):取消内存对齐,或者说是1字节对齐
  __attribute__((aligned(n))):设定结构体类型整体按n字节对齐,注意是整体而不是这个结构体变量内的元素按n字节对齐
  struct mystruct1
  {
  int a;
  char b;
  short c;
  }__attribute__((packed));
  这样这个结构体类型按1字节对齐,所以这个结构体类型占7字节
  123456 struct mystruct2
  {
  int a;
  char b;
  short c;
  }__attribute__((aligned(2))) mystr2;
  (不能是mystr2 __attribute__((aligned(2))) )
  这样mystruct2这个结构体类型按2字节对齐
  (1)__attribute__((packed))使用时直接放在要进行内存对齐的类型定义的后面,然后它起作用的范围只有加了这个东西的这一个类型。packed的作用是取消对齐访问。
  (2)__attribute__((aligned(n)))使用时直接放在要进行内存对齐的类型定义的后面,然后它起作用的范围只有加了这个东西的这一个类型(只能是加在类型后面,不能加在变量后面)。它的作用是让整个结构体变量整体进行n字节对齐(注意是结构体变量整体n字节对齐,而不是结构体内各元素也要n字节对齐)
  结构体字节对齐
  在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题。从理论上讲,对于任何变量的访问都可以从任何地址开始访问,但是事实上不是如此,实际上访问特定类型的变量只能在特定的地址访问,这需要各个变量在空间上按一定的规则排列,而不是简单地顺序排列,这是内存对齐。
  内存对齐的原因:
  1)某些平台只能在特定的地址处访问特定类型的数据;
  2)提高存取数据的速度。比如有的平台每次都是从偶地址处读取数据,对于一个int型的变量,若从偶地址单元处存放,则只需一个读取周期即可读取该变量;但是若从奇地址单元处存放,则需要2个读取周期读取该变量。
  在C99标准中,对于内存对齐的细节没有作过多的描述,具体的实现交由编译器去处理,所以在不同的编译环境下,内存对齐可能略有不同,但是对齐的基本原则是一致的,对于结构体的字节对齐主要有下面两点:
  1)结构体每个成员相对结构体首地址的偏移量(offset)是对齐参数的整数倍,如有需要会在成员之间填充字节。编译器在为结构体成员开辟空间时,首先检查预开辟空间的地址相对于结构体首地址的偏移量是否为对齐参数的整数倍,若是,则存放该成员;若不是,则填充若干字节,以达到整数倍的要求。
  2)结构体变量所占空间的大小是对齐参数大小的整数倍。如有需要会在后一个成员末尾填充若干字节使得所占空间大小是对齐参数大小的整数倍。
  注意:在看这两条原则之前,先了解一下对齐参数这个概念。对于每个变量,它自身有对齐参数,这个自身对齐参数在不同编译环境下不同。下面列举的是两种常见的编译环境下各种类型变量的自身对齐参数
  从上面可以发现,在windows(32)/VC6.0下各种类型的变量的自身对齐参数是该类型变量所占字节数的大小,而在linux(32)/GCC下double类型的变量自身对齐参数是4,是因为linux(32)/GCC下如果该类型变量的长度没有超过CPU的字长,则以该类型变量的长度作为自身对齐参数,如果该类型变量的长度超过CPU字长,则自身对齐参数为CPU字长,而32位系统其CPU字长是4,所以linux(32)/GCC下double类型的变量自身对齐参数是4,如果是在Linux(64)下,则double类型的自身对齐参数是8。
  除了变量的自身对齐参数外,还有一个对齐参数,是每个编译器默认的对齐参数#pragma pack(n),这个值可以通过代码去设定,如果没有设定,则取系统的默认值。在windows(32)/VC6.0下,n的取值可以为1、2、4、8,默认情况下为8。在linux(32)/GCC下,n的取值只能为1、2、4,默认情况下为4。注意像DEV-CPP、MinGW等在windows下n的取值和VC的相同。
  了解了这2个概念之后,可以理解上面2条原则了。对于第一条原则,每个变量相对于结构体的首地址的偏移量必须是对齐参数的整数倍,这句话中的对齐参数是取每个变量自身对齐参数和系统默认对齐参数#pragma pack(n)中较小的一个。举个简单的例子,比如在结构体A中有变量int a,a的自身对齐参数为4(环境为windows/vc),而VC默认的对齐参数为8,取较小者,则对于a,它相对于结构体A的起始地址的偏移量必须是4的倍数。
  对于第二条原则,结构体变量所占空间的大小是对齐参数的整数倍。这句话中的对齐参数有点复杂,它是取结构体中所有变量的对齐参数的大值和系统默认对齐参数#pragma pack(n)比较,较小者作为对齐参数。举个例子假如在结构体A中先后定义了两个变量int a;double b;对于变量a,它的自身对齐参数为4,而#pragma pack(n)值默认为8,则a的对齐参数为4;b的自身对齐参数为8,而#pragma pack(n)的默认值为8,则b的对齐参数为8。由于a的终对齐参数为4,b的终对齐参数为8,那么两者较大者是8,然后再拿8和#pragma pack(n)作比较,取较小者作为对齐参数,也是8,即意味着结构体终的大小必须能被8整除。
  下面是测试例子:
  注意:以下例子的测试结果均在windows(32)/VC下测试的,其默认对齐参数为8
/*测试sizeof运算符  2011.10.1*/
#include <iostream>
using namespace std;
//#pragma pack(4)    //设置4字节对齐
//#pragma pack()     //取消4字节对齐
typedef struct node1
{
int a;
char b;
short c;
}S1;
typedef struct node2
{
char a;
int b;
short c;
}S2;
typedef struct node3
{
int a;
short b;
static int c;
}S3;
typedef struct node4
{
bool a;
S1 s1;
short b;
}S4;
typedef struct node5
{
bool a;
S1 s1;
double b;
int c;
}S5;
int main(int argc, char *argv[])
{
cout<<sizeof(char)<<" "<<sizeof(short)<<" "<<sizeof(int)<<" "<<sizeof(float)<<" "<<sizeof(double)<<endl;
S1 s1;
S2 s2;
S3 s3;
S4 s4;
S5 s5;
cout<<sizeof(s1)<<" "<<sizeof(s2)<<" "<<sizeof(s3)<<" "<<sizeof(s4)<<" "<<sizeof(s5)<<endl;
return 0;
}