C语言结构体对齐

1.结构体变量中的元素如何访问?

(1)数组中元素的访问方式:表面上有2种方式(数组下标方式和指针方式);实质上都是指针方式访问。
(2)结构体变量中的元素访问方式:只有一种,用.或者->的方式来访问。(.和->访问结构体元素其实质是一样的,只是C语言规定用结构体变量来访问元素用. 用结构体变量的指针来访问元素用->。实际上在高级语言中已经不区分了,都用.)
(3)结构体的访问方式有点类似于数组下标的方式

2.利用指针访问结构体元素

  结构体元素地址=结构体首地址+元素偏移量

  

struct mystruct
{
    int a;            
    int b;            

} s1;

//s1.b的地址
int* p=(int*)((int)&s1+4);
*p=5;// s1.b=5;

3.结构体对齐

  一般情况下,为了配合硬件,如果对齐排布和访问会提高效率,否则会大大降低效率。

  (0)、一般编辑器默认4字节对齐。

  (1)、结构体对齐要考虑:结构体整体本身必须安置在4字节对齐处,结构体对齐后的大小必须4的倍数(编译器设置为4字节对齐时,如果编译器设置为8字节对齐,则这里的4是8)
  (2)、结构体中每个元素本身都必须对其存放,而每个元素本身都有自己的对齐规则。
  (3)、编译器考虑结构体存放时,以满足以上2点要求的最少内存需要的排布来算。

struct mystruct1
{                      // 1字节对齐    4字节对齐
    int a;         // 4            4
    char b;              // 1            2(1+1)
    short c;            // 2            2
}; 

struct mystruct11
{                     // 1字节对齐    4字节对齐
    int a;            // 4            4
    char b;           // 1            2(1+1)
    short c;         // 2            2
};

typedef struct mystruct111
{                    // 1字节对齐    4字节对齐        2字节对齐
    int a;            // 4            4                4
    char b;          // 1            2(1+1)            2
    short c;         // 2            2                2
    short d;         // 2            4(2+2)            2
} My111;

typedef struct mystruct2
{                    // 1字节对齐    4字节对齐
    char a;           // 1            4(1+3)
    int b;            // 4            4
    short c;         // 2            4(2+2)
}MyS2;

struct mystruct21
{                    // 1字节对齐    4字节对齐
    char a;            // 1           4(1+3)
    int b;            // 4            4
    short c;          // 2            4(2+2)
} ;
typedef struct myStruct5
{                            // 1字节对齐    4字节对齐
    int a;                    // 4          4
    struct mystruct1 s1;    // 7            8
    double b;                // 8           8
    int c;                    // 4          4    
}MyS5;

struct stu
{                            // 1字节对齐    4字节对齐
    char sex;                // 1            4(1+3)
    int length;                // 4            4
    char name[10];            // 10            12(10+2)
};

4.结构体对齐指令

  以#prgama pack(n)开头,以#pragma pack()结尾,定义一个区间,这个区间内的对齐参数就是n。

#pragma pack(2)

struct s
{
    char c;            //2 (1+1)
    int b;             //4 (4)

} ;
#pragma pack()

  取消对齐访问
  __attribute__((packed));
  设置结构体整体对齐访问(不包含元素)
  __attribute__((aligned(n)));

  

struct mystruct11
{                    // 1字节对齐    4字节对齐
    int a;            // 4            4
    char b;            // 1            2(1+1)
    short c;        // 2            2
}__attribute__((packed));

typedef struct mystruct111
{                    // 1字节对齐    4字节对齐        2字节对齐
    int a;            // 4            4                4
    char b;            // 1            2(1+1)            2
    short c;        // 2            2                2
    short d;        // 2            4(2+2)            2
}__attribute__((aligned(1024))) My111;

5.offsetof宏与container_of宏

offsetof            在0地址处虚拟出一个结构体,通过元素的地址则为偏移量

container_of     通过元素地址减去偏移量得到结构体地址

typeof()传入变量,返回相应的数据类型。
#include<stdio.h>

struct mystruct
{
    char a;
    int b;
    short c;
    
};
// TYPE是结构体类型,MEMBER是结构体中一个元素的元素名
// 这个宏返回的是member元素相对于整个结构体变量的首地址的偏移量,类型是int
#define offsetof(TYPE, MEMBER) ((int) &(((TYPE *)0)->MEMBER))//TYPE *为传入值 

 // ptr是指向结构体元素member的指针,type是结构体类型,member是结构体中一个元素的元素名
// 这个宏返回的就是指向整个结构体变量的指针,类型是(type *)
//typeof() 是通过变量名 返回数据类型的
#define container_of(ptr, type, member) ({            \
    const typeof(((type *)0)->member) * __mptr = (ptr);    \  //定义一个typeof(((type *)0)->member)类型的指针指向 结构体元素地址
    (type *)((char *)__mptr - offsetof(type, member)); })  //元素地址-偏移量=结构体首地址
    //通过元素地址减去偏移量得到结构体地址
int main()
{
    struct mystruct s1;
    struct mystruct *Ps;
    s1.b=12;
    int * pb=&s1.b;
    Ps=container_of(pb,struct mystruct,b);
    printf("container_of宏实例\n");
    printf("&s1=%p\n",&s1);
    printf("Ps=%p\n",Ps);
    
    
    //int *p=(int *)((char*)&s1+4);
    int *p=(int *)((int)&s1+4);
    printf("*p=%d.\n",*p);
    printf("offsetof宏实例\n");
    int offsetof_a=offsetof(struct mystruct,a);
    int offsetof_b=offsetof(struct mystruct,b);
    int offsetof_c=offsetof(struct mystruct,c);
    printf("offsetof_a=%d\n",offsetof_a);
    printf("offsetof_b=%d\n",offsetof_b);
    printf("offsetof_c=%d\n",offsetof_c);
    
    return 0;    
    
}

 

posted @ 2017-01-06 22:14  SongPF  阅读(622)  评论(0编辑  收藏  举报