分类: LINUX
2006-03-23 17:24:12
The GNU manual says,
Without a value specified, pack all structure members together without holes.When a value is specified (which must be a small power of two), pack structure members according to this value, representing the maximum alignment (that is, objects with default alignment requirements larger than this will be output potentially unaligned at the next fitting location.
The GCC compiler ignores "#pragma pack" statement when compiling for ARM platform, so
you should use "__attribute__((packed, aligned))", like this:
#if defined(__WINS__)
#define PACKED
#else
#define PACKED __attribute__((packed, aligned(1)))
#endif
#pragma pack(1)
typedef struct {
char sig[104];
unsigned char verl,key;
int nFile, dFile, crc;
}PACKED avl1;
typedef struct {
char name[22];
int length, crc32;
}PACKED avd1;
#pragma pack(4)
解答:
对于问题1/2:
默认的内存对齐方式以及内存对齐规则在不同的系统上是有区别的,所以GCC编译器在这一点上在不同的系统上也是区别对待的。虽然到现在也没有看到GCC在Linux系统下的使用 #pragma pack(N) 的内存对齐规则,但是从我测试的结果来看是这样:默认的对齐是按照 int 型(4字节)对齐,如果指定 #pragma pack(N) 中的 N 的话,N 不能大于默认对齐指定的长度,即如果默认对齐是 4 的话,N的取值可以是 1、2、4,超过4 之后作为 4 处理。在 Windows 等系统上似乎没有这个限制。
对于gcc在编译时使用 -fpack-struct[=n] 选项
对于问题3:
每个变量占用的空间是由 sizeof 值决定的,所以应该是12而不是16。至于两个变量的地址之差是16而不是12说明了这两个变量是不连续的,中间有“空隙”,但这并不违背C/C++标准。至于这样做的原因,可能是将结构体变量的地址对齐到内存地址是16的倍数的地址上,从而提高结构体的存取效率。
如果你定义一个上述结构体类型的数组然后检查相邻元素的地址,就会发现相邻元素之间是连续的
----------------------------------------------
问题1:
在 GCC4 中 #pragma pack(8) 似乎有问题。
[code]#pragma pack(8)
struct A {
char a; // 1
double b; // 8
};
[/code]
这个结构体的大小在 VC 下得到的是 16(按照8bytes补齐),但是在GCC4(FC4)下得到的是12。我请教了其它朋友,分别试验了Linux + GCC 3.2 和 FreeBSD + GCC
问题2:
#pragma pack(16)
typedef struct t1{
char c;
int d;
} t1;
//#pragma pack(1)
main()
{
t
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(b));
printf("%p\n",&a);
printf("%p\n",&b);
}
[/code]
输出的是
8
8
0xbfffed40
0xbfffed38
为什么sizeof还是8呢
问题3:
再来一个double的问题
[code]
#pragma pack(4)
typedef struct t1{
char c;
double d;
} t1;
main()
{
t
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(b));
printf("%p\n",&a);
printf("%p\n",&b);
}
[/code]
输出的是
12
12
0xbfffed30
0xbfffed20
为什么变量b占用的空间是16个字节呢?
typedef struct test{
char a;
uint16 b;
}TEST
结构TEST在单字节对齐的平台上占内存三个字节,而在以上所述的嵌入式平台上有可能占三个或四个字节,视成员a的存储地址而定。当a存储地址为偶数时,该结构占四个字节,在a与b之间存在一个字节的空洞。对于通信双方都是对结构成员操作的,这种情况不会出错,但如果有一方是逐字节读取内容的(通信协议大都如此),就会错误地读到其它字节的内容。其次,若对内存中数据以强制类型转换的方式读取,字节对齐的不同会引起数据读取的错误。因为假如指针指在基数内存地址处,我们想取得占内存两个字节的数据存放在uint16型的变量中,强制类型转换的结果是取得了该指针所指地址与前一地址处的数据,并没有按照我们的愿望取该指针所指地址与后一地址处的数据,这样就导致了数据读取的错误。
解决字节对齐有许多方法,比如可以在GCC的项目管理文件MakeFile中增加编译选项--pack-struct;但这种方法只能去除结构中的空洞,并不能解决强制类型转换引起的错误。为了增强软件的可移植性以及和同类其它平台产品的互通性,我们在收数据包处增加了拆包的函数,发数据包处增加了组包的函数。这两个函数解决了字节序的问题,也解决了字节对齐的问题。即组包时根据参数中的格式字符串将内存中的不同数据类型的某段数据放在指定地址处,组成包发给下层;拆包时,根据参数中的格式字符串将收到的内存中的数据存放在不同类型的变量或结构成员中。在函数中针对不同的数据类型作不同的处理。