關(guān)于C++中由于字節(jié)對(duì)齊引起內(nèi)存問題定位分析
最近遇到了一個(gè)奇怪的問題,在創(chuàng)建對(duì)象時(shí)程序異常退出,具體地,在構(gòu)造函數(shù)中訪問類中最后一個(gè)成員變量時(shí),程序異常退出。
問題定位
查看代碼,發(fā)現(xiàn)該類中有一個(gè)結(jié)構(gòu)體數(shù)組,該結(jié)構(gòu)體在類的外面聲明,用 #pragma pack(push,1) 設(shè)置了一字節(jié)對(duì)齊方式,而類不在這個(gè)作用范圍內(nèi),所以是按照默認(rèn)字節(jié)對(duì)齊方式的。懷疑該問題是因?yàn)?,類的字?jié)對(duì)齊方式和類中的結(jié)構(gòu)體字節(jié)方式不同引起的。但這從理論方面解釋不通。
繼續(xù)定位,在創(chuàng)建對(duì)象之前用sizeof打印類的大小,再在類的構(gòu)造函數(shù)中打印類的大小。發(fā)現(xiàn)這兩個(gè)大小居然不同。這證實(shí)了的確與字節(jié)對(duì)齊有關(guān),創(chuàng)建對(duì)象之前和在構(gòu)造函數(shù)中,兩邊選擇的字節(jié)對(duì)齊方式不同,導(dǎo)致計(jì)算類的大小不同。
但是為什么這兩個(gè)地方的字節(jié)對(duì)齊方式不同呢?
當(dāng)把該類也使用 #pragma pack(push,1) 設(shè)置字節(jié)對(duì)齊方式之后,類的大小又變得相同了。大膽猜測(cè),由于 #pragma pack(push, 1) 是一種棧的結(jié)構(gòu),可能有某個(gè)文件中,設(shè)置了字節(jié)對(duì)齊方式之后,沒有用 #pragma pack(pop) 恢復(fù)。
查找全局文件,的確找到了一個(gè)文件存在這樣的問題,當(dāng)把 #pragma pack(pop) 后加上后,問題解決。
問題模型
我將這個(gè)問題簡化成下面這樣,可以幫助大家更好地理解。
CA.h,CA類的聲明,模擬只push,沒pop的文件
#ifndef CA_H #define CA_H #include <iostream> using namespace std; #pragma pack(push, 1) class CA { int a; char b; }; #endif
CB.h,CB類的聲明。St結(jié)構(gòu)體設(shè)置一字節(jié)對(duì)齊方式,CB類使用默認(rèn)字節(jié)對(duì)齊方式。
#ifndef CB_H #define CB_H #include <iostream> using namespace std; #pragma pack(push,1) struct St { int a1; int a2; int a3; char a4; char a5; }; #pragma pack(pop) class CB { public: CB(); int a1; int a2; int a3; char a4; char a5; St a6[10]; bool a7; }; #endif
CB.cpp,CB類的實(shí)現(xiàn)。
#include "CB.h" #include <iostream> using namespace std; CB::CB() { cout << "constructor: sizeof(CB) = "; cout << sizeof(CB) << endl; }
main.cpp,用于創(chuàng)建CB對(duì)象
#include "CA.h" #include "CB.h" #include <iostream> using namespace std; int main() { cout << "main: sizeof(CB) = "; cout << sizeof(CB) << endl; CB *pCB = new CB; }
編譯上述文件并執(zhí)行,可以得到下面的結(jié)果:
main: sizeof(CB) = 155
constructor: sizeof(CB) = 156
可以看到,兩處計(jì)算的類的大小是不同的。在main函數(shù)里,分配了155字節(jié)的空間,而在構(gòu)造函數(shù)中卻認(rèn)為有156字節(jié)的空間,當(dāng)訪問最后一字節(jié)時(shí),程序出現(xiàn)了踩內(nèi)存。
問題分析
為什么main.cpp和CB.cpp認(rèn)為CB的字節(jié)對(duì)齊方式不同呢?
這主要還是因?yàn)閙ain.cpp包含了CA.h,CA.h在main.cpp中展開,CB.h也展開,CA.h中設(shè)置的一字節(jié)對(duì)齊方式,影響到了CB類的聲明,當(dāng)編譯main.cpp時(shí),CB使用一字節(jié)對(duì)齊方式。
而CB.h沒有包含CA.h,當(dāng)編譯CB.cpp時(shí),并沒有受到CA.h的影響,CB使用默認(rèn)字節(jié)對(duì)齊方式。
以上就是關(guān)于C++中由于字節(jié)對(duì)齊引起內(nèi)存問題定位分析的詳細(xì)內(nèi)容,更多關(guān)于c++字節(jié)對(duì)齊內(nèi)存問題的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
stl常用算法(Algorithms)介紹(stl排序算法、非變序型隊(duì)列)
這篇文章主要介紹了stl常用算法(Algorithms)介紹(stl排序算法、非變序型隊(duì)列),需要的朋友可以參考下2014-05-05C++實(shí)踐排序函數(shù)模板項(xiàng)目的參考方法
今天小編就為大家分享一篇關(guān)于C++實(shí)踐排序函數(shù)模板項(xiàng)目的參考方法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-02-02標(biāo)準(zhǔn)CSV格式的介紹和分析以及解析算法實(shí)例詳解
這篇文章主要介紹了標(biāo)準(zhǔn)CSV格式的介紹和分析以及解析算法實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2016-12-12C語言編程中常見的五種錯(cuò)誤及對(duì)應(yīng)解決方案
這篇文章主要給大家分享的是C語言編程中常見的五種錯(cuò)誤及對(duì)應(yīng)解決方案,詳細(xì)內(nèi)容就請(qǐng)跟小編一起進(jìn)入下面的文章內(nèi)容吧2021-10-10