#include <stdio.h>
#pragma pack(16)
typedef struct t1{
char c;
int d;
short a;
} t1;
void main(void)
{
t1 a;
a.c = 'a';
a.d = 1;
a.a = 3;
printf("sizeof t1=%d",sizeof(t1));
}
我们先不看具体结果是什么,先来回忆下具体的在这些结构体中的字节对齐的问题。正常char类型1个字节,short 2个字节,int 4个字节,在GCC 3.0或VC6.0的编译器下是这样的,正常思维应该是7个字节,但编译器此时会按照系统的默认的对齐方式,#pragma pack()这种方式默认对齐,此时char 类型占有字节数为1,需要补齐3字节,由低地址向高地址扩展,即char 向int 扩展,同理short也需向int 扩展,此时需补齐2个字节。为了能够防止上面的默认对齐方式,可以加上#pragma pack(1)按一字节进行对齐,此时的结果就是7字节了。当然说了这些只是告诉你,编译器系统会有一个字节默认对齐方式。结构体的变量顺序不同也会导致大小不一样,比如讲上述结构体改以下:
typedef struct t1{
short a;
char c;
int d;
} t1;//sizeof(t1)结果又会是多少呢?按照我上面说的,我想大家很快就能知道了。short向char扩展,char又向int扩展,所以结果为8个字节。
说了这些也行某些人对#pragma pack()这个宏不了解,具体是干什么的呢?首先来看一下#pragma pack的原型:#pragma pack( [show] | [push | pop] [, identifier], n )
语法具体分析:
1,show:可选参数;显示当前packing aligment的字节数,以warning message的形式被显示;
2,push:可选参数;将当前指定的packing alignment数值进行压栈操作,这里的栈是the internal compiler
stack,同时设置当前的packing alignment为n;如果n没有指定,则将当前的packing alignment数值压栈;
3,pop:可选参数;从internal compiler
stack中删除最顶端的record;如果没有指定n,则当前栈顶record即为新的packing
alignment数值;如果指定了n,则n将成为新的packing aligment数值;如果指定了identifier,则internal
compiler,stack中的record都将被pop直到identifier被找到,然后pop出identitier,同时设置packing,alignment 数值为当前栈顶的record;如果指定的identifier并不存在于internal compiler stack,则pop操作被忽略;
4,identifier:可选参数;当同push一起使用时,赋予当前被压入栈中的record一个名称;当同pop一起使用时, 从 internal compiler
stack中pop出所有的record直到identifier被pop出,如果identifier没有被找到,则忽略pop操作;
5,n:可选参数;指定packing的数值,以字节为单位;缺省数值是8,合法的数值分别是1、2、4、8、16。
以上这个是我从网上摘录的。需要注意的是n取值范围只有那些值,这是跟数据类型所占的空间来的,记住这个就OK了。
现在开始说我上面的面试题的答案了,输出的是12个字节。有人说不是已经执行了#pragma pack(16)了吗?为什么不是全按16字节对齐呢?由于结构体中最大的数据类型是int,所以你设成超过4字节对齐方式都是一样的。