内存对齐计算

1,484 阅读3分钟

结构体内存对接


基本数据类型的占用内存

typebyte size (64位系统)byte size (32位)
bool11
char11
short22
int44
long84
long long88
float44
double88

计算

// 注释为内存地址
struct T1 {
    double a;  // 0 - 7
    char b;    // 8 - 8
    int c;     // 12 - 15 (参见规则 1,每个成员的起始位置为必须为当前成员大小的整数倍,因为9不能被4整除 ...)
    short d;   // 16 - 17
} t1; // size: 24  (参见规则 3, (18 + (8 - 1)) >> 3 << 3 = 24 )

struct T2 {
    double a;   // 0 - 7
    int b;      // 8 - 11
    char c;     // 12 - 12
    short d;    // 14 - 15
} t2; // size: 16

struct T3 {
    double a; 		 // 0 - 7
    int b;     		 // 8 - 11
    char c;             // 12 - 12
    short d;            // 14 - 15
    struct T1 e;        // (24) 16 - 39  (参见规则 2,倍数为 T1 的的最大成员 double 8)
} t3; // size: 40

注:在64位系统中

内存对齐计算规则:

1、数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第⼀个数据成员放在offset为0的地⽅,以后每个数据成员存储的起始位置要从该成员⼤⼩或者成员的⼦成员⼤⼩(只要该成员有⼦成员,⽐如说是数组,结构体等)的整数倍开始(⽐如int为4字节,则要从4的整数倍地址开始存储。

2、结构体作为成员:如果⼀个结构⾥有某些结构体成员,则结构体成员要从其内部最⼤元素⼤⼩的整数倍地址开始存储。(struct a⾥存有struct b,b⾥有char、int 、double等元素,那b应该从8的整数倍开始存储。)

3、收尾⼯作:结构体的总⼤⼩,也就是sizeof的结果,必须是其内部最⼤成员的整数倍,不⾜的要补⻬。

解析 :
1、 变量a:**double ** 占8个字节,从0位置开始,则 0-7 存储 a
2、变量b:**char **占1个字节,从8位置开始,此时8是1的整数倍,则 8 存储 b
3、变量c:int 占4个字节,从9位置开始,但是此时9不是4的整数倍,因此需要往后继续寻找,找到最接近的能整除4的12位置,则 12-15 存储 c
4、变量d:**short **占2个字节,从16位置开始,此时16是2的整数倍,则16-17 存储 d
5、收尾:T1需要的内存大小为18字节,而T1中最⼤成员变量字节数是8字节,内存大小18字节不是内部最⼤成员的整数倍,所以必须向上补齐,补齐后的最终大小为24字节

【end】模拟计算结构体大小 -- 不考虑嵌套

struct T1 {
    double a;  
    char b;    
    int c;     
    short d;  
} t1; // size: 24  

int _memberSizeOffset(int value) {
    int offset = 0; //计算位移值 二进制幂 2^3 >> 3
    while (value != 0) {
        value = value >> 1;
        offset ++;
    }
    if (offset > 0) {
        offset --;
    }
    return offset;
}
int calculateStructMemorySize(int structMemory[], int length) {
	int structMemorySize = 0; // 结构体内存大小
        int maxMemberSize = 0; // 最大成员变量长度
        for (int i = 0; i < length; i++) {
            int memberSize = structMemory[i];
            maxMemberSize = MAX(maxMemberSize, memberSize);
            
            if (structMemorySize % memberSize != 0) {
                // 内存对齐
                int offset = _memberSizeOffset(memberSize); //计算位移值 二进制幂 2^3 >> 3
                structMemorySize = (structMemorySize + memberSize - 1) >> offset << offset;
            }
            
            structMemorySize += memberSize;
        }
        if (structMemorySize % maxMemberSize != 0) {
            int offset = _memberSizeOffset(maxMemberSize); //计算位移值
            structMemorySize = (structMemorySize + maxMemberSize - 1) >> offset << offset;
        }
        return structMemorySize;
}
int main() {
	// 现在不考虑结构体嵌套情况
        int structMemory[] = {8, 1, 4, 2}; // 结构体的成员大小数组
        int length = sizeof(structMemory) / sizeof(int); // 数组长度
        
        int structMemorySize = calculateStructMemorySize(structMemory, length);
        
        printf("内存大小:%d\n", structMemorySize);

	return 0;
}