1、CPU读取内存数据

         计算机的内存系统通常以为单位进行数据传输32位系统是4字节,64位系统是8字节。

  当数据存储在对齐的地址上时,数据的起始地址正好是内存块的边界,CPU可以一次性读取完整的数据。

(1)对齐数据的访问

    ①如果int变量存储在地址0x1000,那么CPU可以一次读取从 0x1000~0x1003 的4字节数据

    ②如果double变量存储在地址0x2000,那么CPU可以一次读取从 0x2000~0x2007 的8字节数据

(2)未对齐数据的访问

       ① 如果int变量存储在地址0x1001,那么CPU分两次读取:0x1001~0x1003  +  0x1004

       ② 如果double变量存储在地址0x2002,那么CPU分两次读取:0x2002~0x2007 + 0x2008~0x2009

        

2、内存对齐原则

(1)第一个成员偏移0,之后每个成员的起始位置是当前成员的整数倍;

(2)如果结构体A中含有结构体B,B的起始位置是B中最大元素大小整数倍;

(3)结构体总大小是内部最大成员的整数倍。

系统默认的字节对齐值:32位系统是4字节,64位系统是8字节。

 

3、示例代码1

#include <stdio.h>
#include <string.h>

#define PRINT_SIZE(intValue) printf(#intValue" is %d\n",(intValue));
#define STRUCT_MEMBER_OFFSET(type, member)     ( (char*) & ((type*)0)->member - (char*)0 )

struct employee
{
    char *name;
    int num;
    short age;
    char evaluation;
    char *department;
};

int main()
{
    PRINT_SIZE(sizeof(struct employee));
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct employee, name));
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct employee, num));
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct employee, age));
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct employee, evaluation));
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct employee, department));
    return 0;
}

执行结果:

sizeof(struct employee) is 24
STRUCT_MEMBER_OFFSET(struct employee, name) is 0
STRUCT_MEMBER_OFFSET(struct employee, num) is 8
STRUCT_MEMBER_OFFSET(struct employee, age) is 12
STRUCT_MEMBER_OFFSET(struct employee, evaluation) is 14
STRUCT_MEMBER_OFFSET(struct employee, department) is 16

4、示例代码2

#include <stdio.h>
#include <string.h>

#define PRINT_SIZE(intValue) printf(#intValue" is %d\n",(intValue));
#define STRUCT_MEMBER_OFFSET(type, member)     ( (char*) & ((type*)0)->member - (char*)0 )

struct student
{
    char name[10];
    int num;
    char sex;
};

int main()
{
    PRINT_SIZE(sizeof(struct student))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct student, name))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct student, num))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct student, sex))
    return 0;
}

执行结果

PS D:\Code\Data Structure> .\test.exe
sizeof(struct student) is 20
STRUCT_MEMBER_OFFSET(struct student, name) is 0
STRUCT_MEMBER_OFFSET(struct student, num) is 12
STRUCT_MEMBER_OFFSET(struct student, sex) is 16

 

5、两种字节对齐方式

(1)#pragma pack(n)  

    ① 指定structunion成员的对齐边界为 n 字节

    ② n的取值为2的幂数,1, 2, 4, 8, 16

    ③ 如果没有指定#pragma pack,编译器会根据目标平台的默认对齐值4字节或者8字节;

    ④ n默认对齐值较小值 进行对齐

#pragma pack(1)
struct Example 
{
    char a;       // 1字节
    int b;        // 4字节
    short c;      // 2字节
};
#pragma pack()

n取1时,紧凑排列, Example结构体的大小=7 

#pragma pack(2)
struct Example 
{
    char a;       // 1字节
    int b;        // 4字节
    short c;      // 2字节
};
#pragma pack()

 n取2时,Example结构体的大小=8 

 

(2)__attribute__( aligned(n) ) 

 编译器会将让n默认的对齐字节数进行比较,取较大值为对齐字节数

 

(3)__attribute__( (packed) ) 

取消结构在编译过程中的优化对齐, 等同于#pragma pack(1)  

 

#include <stdio.h>
#include <string.h>
 
#define PRINT_SIZE(intValue) printf(#intValue" is %ld\n",(intValue));
#define STRUCT_MEMBER_OFFSET(type, member)     ( (char*) & ((type*)0)->member - (char*)0 )
 
typedef struct mystruct_packed
{
    int a;   
    double b;
    char c;  
}__attribute__((packed)) AP;
 
typedef struct mystruct2
{            
    int a;   
    double b;
    char c;  
}__attribute__((aligned(2))) A2;

typedef struct mystruct4
{            
    int a;   
    double b;
    char c;  
}__attribute__((aligned(4))) A4;
 
typedef struct mystruct8
{            
    int a;   
    double b;
    char c;  
}__attribute__((aligned(8))) A8;
 
typedef struct mystruct16
{            
    int a;   
    double b;
    char c;  
}__attribute__((aligned(16))) A16;
 
typedef struct mystruct32
{            
    int a;   
    double b;
    char c;  
}__attribute__((aligned(32))) A32;
 
int main()
{
    PRINT_SIZE(sizeof(struct mystruct_packed))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct_packed, a))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct_packed, b))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct_packed, c))
    printf("\n");
    
    PRINT_SIZE(sizeof(struct mystruct2))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct2, a))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct2, b))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct2, c))    
    printf("\n");
    
    PRINT_SIZE(sizeof(struct mystruct4))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct4, a))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct4, b))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct4, c))    
    printf("\n");  
      
    PRINT_SIZE(sizeof(struct mystruct8))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct8, a))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct8, b))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct8, c))    
    printf("\n");
    
    PRINT_SIZE(sizeof(struct mystruct16))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct16, a))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct16, b))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct16, c))    
    printf("\n");
    
    PRINT_SIZE(sizeof(struct mystruct32))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct32, a))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct32, b))
    PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct32, c))    
 
    return 0;
}

 

执行结果:

xuanmiao@linux:~/Test$ ./test
sizeof(struct mystruct_packed) is 13
STRUCT_MEMBER_OFFSET(struct mystruct_packed, a) is 0
STRUCT_MEMBER_OFFSET(struct mystruct_packed, b) is 4
STRUCT_MEMBER_OFFSET(struct mystruct_packed, c) is 12

sizeof(struct mystruct2) is 24
STRUCT_MEMBER_OFFSET(struct mystruct2, a) is 0
STRUCT_MEMBER_OFFSET(struct mystruct2, b) is 8
STRUCT_MEMBER_OFFSET(struct mystruct2, c) is 16

sizeof(struct mystruct4) is 24
STRUCT_MEMBER_OFFSET(struct mystruct4, a) is 0
STRUCT_MEMBER_OFFSET(struct mystruct4, b) is 8
STRUCT_MEMBER_OFFSET(struct mystruct4, c) is 16

sizeof(struct mystruct8) is 24
STRUCT_MEMBER_OFFSET(struct mystruct8, a) is 0
STRUCT_MEMBER_OFFSET(struct mystruct8, b) is 8
STRUCT_MEMBER_OFFSET(struct mystruct8, c) is 16

sizeof(struct mystruct16) is 32
STRUCT_MEMBER_OFFSET(struct mystruct16, a) is 0
STRUCT_MEMBER_OFFSET(struct mystruct16, b) is 8
STRUCT_MEMBER_OFFSET(struct mystruct16, c) is 16

sizeof(struct mystruct32) is 32
STRUCT_MEMBER_OFFSET(struct mystruct32, a) is 0
STRUCT_MEMBER_OFFSET(struct mystruct32, b) is 8
STRUCT_MEMBER_OFFSET(struct mystruct32, c) is 16

 

posted on 2025-02-25 18:36  轩~邈  阅读(92)  评论(0)    收藏  举报