将程序中的每个数据单元
安排在适当的位置
上(这是编译器干的事)
编译器将程序中的每个数据单元
安排在合适的位置上,C语言的灵活性允许程序员干预内存对齐
,如果想要了解更加底层的秘密,就不应该继续对内存对齐保持透明了
以下所有程序的运行环境都是windows 7,Dev-C++ IDE,编译器版本是TDM-GCC 4.9.2 64-bit Debug
//内存对齐计算验证实例
#include
#include
typedef struct test{
char a;
int b;
double c;
char d;
}Test;
int main(int argc, char ** argv)
{
Test T;
int offset_a = offsetof(Test, a);
int offset_b = offsetof(Test, b);
int offset_c = offsetof(Test, c);
int offset_d = offsetof(Test, d);
printf("The length of char type is %u\n", sizeof(char));
printf("The length of int type is %u\n", sizeof(int));
printf("The length of double type is %u\n\n", sizeof(double));
printf("The length of the whole struct is %u\n\n", sizeof(T));
printf("The offset of first data member is %d\n", offset_a);
printf("The offset of second data member is %d\n", offset_b);
printf("The offset of third data member is %d\n", offset_c);
printf("The offset of fourth data member is %d\n\n", offset_d);
printf("The begin address of first data member of struct test is %p\n", &(T.a));
printf("The begin address of second data member of struct test is %p\n", &(T.b));
printf("The begin address of third data member of struct test is %p\n", &(T.c));
printf("The begin address of fourth data member of struct test is %p\n\n", &(T.d));
return 0;
}
以空间换时间
)对于内存对齐问题,主要存在于struct和union
等复合结构在内存中的分布情况中(或者说在这两种复合结构中内存对齐的影响比较明显)
原则1
:对于struct和union来说,其第一个数据成员要放在offset==0
的地方。如果第一个数据成员为某个复合结构的子成员,则要根据子成员的类型存放在对应的整数倍的地址上原则2
:结构体成员按自身长度自然对齐
(所谓自然对齐,指的是该成员的起始位置的内存地址必须是它自身长度的整数倍)。如果结构体作为成员,则要找到这个结构体中的最大元素,然后从这个最大成员长度的整数倍地址开始存储原则3
:结构体的总大小为结构体的有效对齐值
的整数倍结构体的有效对齐值
的确定:
#pragma pack(n)
指定时,以n和结构体中最长成员的长度中较小者为其有效对齐值__attribute__ ((__packed__))
指定长度时,强制按照此值为结构体的有效对齐值编译器为了满足内存对齐要求,会在各个数据成员之间留下额外的内存空间,这会造成很小的浪费。但是这种浪费是可以容忍的
offset地址的选取
有影响)#pragma pack
和__attribute__
如何指定,结构内部数据成员的自对齐仍然按照其自身的长度来对齐#include
#include
typedef struct test{
int a; //原则1
double b; //原则2
float c; //原则3
}Test;
int main(int argc, char ** argv)
{
Test T;
int offset_a = offsetof(Test, a);
int offset_b = offsetof(Test, b);
int offset_c = offsetof(Test, c);
printf("The length of int type is %u\n", sizeof(int));
printf("The length of double type is %u\n", sizeof(double));
printf("The length of float type is %u\n\n", sizeof(float));
printf("The length of the whole struct is %u\n\n", sizeof(T));
printf("The offset of first data member is %d\n", offset_a);
printf("The offset of second data member is %d\n", offset_b);
printf("The offset of third data member is %d\n\n", offset_c);
printf("The begin address of first data member of struct test is %p\n", &(T.a));
printf("The begin address of second data member of struct test is %p\n", &(T.b));
printf("The begin address of third data member of struct test is %p\n\n", &(T.c));
return 0;
}
#include
#include
typedef struct test{
int a;
double b;
float c;
}Test;
typedef struct test1{
char a[2];
int b;
double c;
short d;
Test e;
}Test1;
int main(int argc, char ** argv)
{
Test1 T;
int offset_a = offsetof(Test1, a);
int offset_b = offsetof(Test1, b);
int offset_c = offsetof(Test1, c);
int offset_d = offsetof(Test1, d);
int offset_e = offsetof(Test1, e);
printf("The length of char type is %u\n", sizeof(char));
printf("The length of int type is %u\n", sizeof(int));
printf("The length of double type is %u\n", sizeof(double));
printf("The length of short type is %u\n", sizeof(short));
printf("The length of Test type is %u\n\n", sizeof(Test));
printf("The length of the whole struct is %u\n\n", sizeof(T));
printf("The offset of first data member is %d\n", offset_a);
printf("The offset of second data member is %d\n", offset_b);
printf("The offset of third data member is %d\n", offset_c);
printf("The offset of fourth data member is %d\n", offset_d);
printf("The offset of fifth data member is %d\n\n", offset_e);
printf("The begin address of first data member of struct test is %p\n", &(T.a));
printf("The begin address of second data member of struct test is %p\n", &(T.b));
printf("The begin address of third data member of struct test is %p\n", &(T.c));
printf("The begin address of third data member of struct test is %p\n", &(T.d));
printf("The begin address of third data member of struct test is %p\n\n", &(T.e));
return 0;
}
//不同的编译器会对内存的分布进行优化,例如有的编译器可能会将该程序优化成下一个程序
//这是属于编译器的问题,这里不做详细的讨论
//尽量在保持代码清晰的情况下,自己手动将该程序优化为下一个程序那样
//如果是单纯的做题,不用考虑编译器的优化问题,一切按照理论进行计算
#include
#include
typedef struct test{
char a;
int b;
char c;
}Test;
int main(int argc, char ** argv)
{
Test T;
int offset_a = offsetof(Test, a);
int offset_b = offsetof(Test, b);
int offset_c = offsetof(Test, c);
printf("The length of char type is %u\n", sizeof(char));
printf("The length of int type is %u\n\n", sizeof(int));
printf("The length of the whole struct is %u\n\n", sizeof(T));
printf("The offset of first data member is %d\n", offset_a);
printf("The offset of second data member is %d\n", offset_b);
printf("The offset of third data member is %d\n\n", offset_c);
printf("The begin address of first data member of struct test is %p\n", &(T.a));
printf("The begin address of second data member of struct test is %p\n", &(T.b));
printf("The begin address of third data member of struct test is %p\n\n", &(T.c));
return 0;
}
#include
#include
typedef struct test{
char a;
char b;
int c;
}Test;
int main(int argc, char ** argv)
{
Test T;
int offset_a = offsetof(Test, a);
int offset_b = offsetof(Test, b);
int offset_c = offsetof(Test, c);
printf("The length of char type is %u\n", sizeof(char));
printf("The length of int type is %u\n\n", sizeof(int));
printf("The length of the whole struct is %u\n\n", sizeof(T));
printf("The offset of first data member is %d\n", offset_a);
printf("The offset of second data member is %d\n", offset_b);
printf("The offset of third data member is %d\n\n", offset_c);
printf("The begin address of first data member of struct test is %p\n", &(T.a));
printf("The begin address of second data member of struct test is %p\n", &(T.b));
printf("The begin address of third data member of struct test is %p\n\n", &(T.c));
return 0;
}
#include
#include
#pragma pack(2)
typedef struct test{
char a;
int b;
char c;
}Test;
int main(int argc, char ** argv)
{
Test T;
int offset_a = offsetof(Test, a);
int offset_b = offsetof(Test, b);
int offset_c = offsetof(Test, c);
printf("The length of char type is %u\n", sizeof(char));
printf("The length of int type is %u\n\n", sizeof(int));
printf("The length of the whole struct is %u\n\n", sizeof(T));
printf("The offset of first data member is %d\n", offset_a);
printf("The offset of second data member is %d\n", offset_b);
printf("The offset of third data member is %d\n\n", offset_c);
printf("The begin address of first data member of struct test is %p\n", &(T.a));
printf("The begin address of second data member of struct test is %p\n", &(T.b));
printf("The begin address of third data member of struct test is %p\n\n", &(T.c));
return 0;
}