C++内存对齐详解(附自己写的代码算法),不同对齐规则通用算法

对齐规则只有1,2,4,8,16, 如果面试写了3,5,6,7等等都是错误的,至少我的编译器没通过。

用C++写的代码如下,因为里面写了注释,所以就不赘述了:

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <string.h>
#include <memory>
#include <typeinfo>
#include <algorithm>


#define N 4
#pragma pack(4)


static int nextAddr = 0;
static int maxPack = 0;


using AlignMem = struct AlignMem {
char ch1[1];
short s;
char ch;
double d;
char ch2[9];
int i;
};


bool isCharType(decltype(typeid(char)) Type) {
return (NULL != strstr(Type.name(), "_c") || typeid(char) == Type);
}


/* 算法參照規則:
 * 1. char類型的直接計算地址,不用考慮對齊情況
 * 2. 非char類型的,根據其存放的開始地址計算,取自身類型和pack對齊規則中較小值,
 *    如果存放開始地址可以整除較小值,則無需補字節; 否則補齊字節,直到可以整除爲止.
 * 3. 結構體整體對齊計算,結構體中非char成員類型最大值與pack對齊規則要求值兩者中較小值,
 *    用最後算出的地址整除該值,如果整除則無需補齊字節,否則補齊字節,直到可以整除爲止.
 * 例如計算AlignMem:
 *    存放s後, 則short存放地址爲1, sizeof(short) < 4(pack裏面的對齊值),所以應該按照2對齊,
 *    因此1補齊1個字節後等於2,那麼short存放地址就是2開始,下一個ch存放地址就是2 + sizeof(short)=4,
 *    按照上述方式依次計算,最終應該是這樣:
 *      (0+sizeof(ch1) + 1)
 *      (sizeof(s))
 *      (sizeof(ch) + 3)
 *      (sizeof(d))
 *      (sizeof(ch2) + 3)

 *      (sizeof(i))

 *      上面算完正好是32, 结构体最大类型是double=8, 对齐规则是4字节对齐,其它俩中最小值进行结构体整体对齐,

 *      也就是用 32 % 4 = 0,所以不用补齐,但是如果计算出来的是33,那么就要补齐了,应该补齐到36.

  * */
template <typename T, typename TI>
void calculateMem(T& typeID, TI typeLength) {
if (typeLength <= 0 && 0 == nextAddr) {
return;
}
int diff = 0;
int n = 0;
/* N          - pack()要求對齊的值
* typeLength - 當前類型的大小
* maxPack    - 找出並保存結構體成員類型(非char)佔用最大的值
* */
if(!isCharType(typeID))
maxPack =  maxPack > typeLength ? maxPack : typeLength;
// n 爲對齊規則,當自身對齊時, n應該使用
// pack() 與 自身類型較小的值.
if (typeLength > 0)
n = N > typeLength ? typeLength : N;
// n 爲對齊規則,當整體對齊時, n應該使用
// pack() 與結構體中類型最大的那個較小的值.
else
n = maxPack > N ? N : maxPack;
// 當typeLength小於等於0時,認爲是沒有要計算佔用空間的類型,即認爲結構體結束
if(typeLength <= 0) {
// nextAddr % n 不爲0表示需要整體補齊
if(nextAddr % n) {
diff = n - (nextAddr % n);
nextAddr = nextAddr + diff;
}
return ;
}
/* 上面做了兩件事:
* 1. 對齊的值n的計算
* 2. 結構體結束(typeLength <= 0)時,整體補齊
*
* 下面做了兩件事:
* 1. 處理不需要對齊的情況
* 2. 處理需要自身對齊的情況
* */
if(0 == nextAddr
  || ((nextAddr % n + typeLength) <= n )) {
nextAddr = nextAddr + typeLength;
return ;
}


if(!isCharType(typeID) && nextAddr % n) {
diff = n - (nextAddr % n);
}
nextAddr = nextAddr + diff + typeLength;
}


int main() {


// 測試部分
AlignMem alignmem;
printf("sizeof AlignMem = %lu\n",sizeof(alignmem));
        calculateMem<decltype(typeid(alignmem.ch1)), decltype(sizeof(alignmem.ch1))>(typeid(alignmem.ch1), sizeof(alignmem.ch1));
        calculateMem<decltype(typeid(alignmem.s)), decltype(sizeof(alignmem.s))>(typeid(alignmem.s), sizeof(alignmem.s));
        calculateMem<decltype(typeid(alignmem.ch)), decltype(sizeof(alignmem.ch))>(typeid(alignmem.ch), sizeof(alignmem.ch));
        calculateMem<decltype(typeid(alignmem.d)), decltype(sizeof(alignmem.d))>(typeid(alignmem.d), sizeof(alignmem.d));
        calculateMem<decltype(typeid(alignmem.ch2)), decltype(sizeof(alignmem.ch2))>(typeid(alignmem.ch2), sizeof(alignmem.ch2));
        calculateMem<decltype(typeid(alignmem.i)), decltype(sizeof(alignmem.i))>(typeid(alignmem.i), sizeof(alignmem.i));
// 這裏要傳0l下去,因爲我是按照0L表示結構體結束,不然的話會缺少整體對齊
        calculateMem<decltype(typeid(int)), decltype(sizeof(int))>(typeid(int), 0L);
printf("calculateMem alignmem = %d\n",nextAddr);
nextAddr = 0;


return EXIT_SUCCESS;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值