一、為什麼要字對齊?
現代計算機中記憶體空間都是按照byte劃分的,從理論上講似乎對任何型別的變數的訪問都可以從任何位址開始,但實際情況是在訪問特定型別變數的時候經常在特定的記憶體位址訪問,這就是對齊。
位元組對齊的原因大致是如下兩條:
1、平台原因(移植原因):不是所有的硬體平台都能訪問任意位址上的任意資料的;某些硬體平台只能在某些位址處取某些特定型別的資料,否則丟擲硬體異常。
2、效能原因:資料結構(尤其是棧)應該盡可能地在自然邊界上對齊。原因在於,為了訪問未對齊的記憶體,處理器需要作兩次記憶體訪問;而對齊的記憶體訪問僅需要一次訪問。
二、對齊規則
每個特定平台上的編譯器都有自己的預設「對齊係數」(也叫對齊模數)。程式設計師可以通過預編譯命令#pragma pack(n),n=1,2,4,8,16來改變這一係數,其中的n就是你要指定的「對齊係數」。
規則:1. 資料成員對齊規則:結構(struct)(或聯合(union))的資料成員,第乙個資料成員放在offset為0的地方,以後每個資料成員的對齊按照#pragma pack指定的數值和這個資料成員自身長度中,比較小的那個進行。
2. 結構(或聯合)的整體對齊規則:在資料成員完成各自對齊之後,結構(或聯合)本身也要進行對齊,對齊將按照#pragma pack指定的數值和結構(或聯合)最大資料成員長度中,比較小的那個進行。
3. 結合1、2可推斷:第
一、如果n大於等於該變數所占用的位元組數,那麼偏移量必須滿足預設的對齊方式,第
二、如果n小於該變數的型別所占用的位元組數,那麼偏移量為n的倍數,不用滿足預設的對齊方式。
四、arm平台的對齊問題
在arm中,有arm和thumb兩種指令。
arm指令:每執行一條指令,pc的值加4個位元組(32bits).一次訪問4位元組內容,該位元組的起始位址必須是4位元組對齊的位置上,即位址的低兩位為bits[0b00],也就是說位址必須是4的倍數。
thumb指令:每執行一條指令,pc的值加2個位元組(16bits).).一次訪問2位元組內容,該位元組的起始位址必須是2位元組對齊的位置上,即位址的低兩位為bits[0b0],也就是說位址必須是2的倍數。
遵循以上方式叫對齊(aligned)方式,不遵守這樣方式稱為非對齊(unaligned)的儲存訪問操作。
五、arm平台位元組對齊關鍵字
1. __align(num)
用於修改最高端別物件的位元組邊界。
a、在彙編中使用ldrd或者strd時,就用到此命令__align(8)進行修飾限制。來保證資料物件是相應對齊。
b、該修飾物件的命令最大是8個位元組限制,可讓2位元組的物件進行4位元組
對齊,但是不能讓4位元組的物件2位元組對齊。
c、 __align是儲存類修改,他只修飾最高端型別物件不能用於結構或者函式物件。
2. __packed
__packed是進行一位元組對齊。
a、不能對packed的物件進行對齊;
b、所有物件的讀寫訪問都進行非對齊訪問;
c、float及包含float的結構聯合及未用__packed的物件將不能位元組對齊;
d、__packed對區域性整形變數無影響;
d、強制由unpacked物件向packed物件轉化是未定義,整形指標可以合法定
義為packed __packed int* p; //__packed int 則沒有意義。
3. __unaligned
用於修飾該變數可按照非對齊訪問。
new關鍵字 this關鍵字 base關鍵字
使用new,所做的三件事 1.類是引用物件,引用物件是在堆中開闢空間 在堆中開闢空間 2.在開闢的堆空間中建立物件 3.呼叫物件的構建函式 4.隱藏父類成員 子類的成員可以與隱藏從父類繼承的成員,類似於重寫。public new void sayhello this關鍵字的使用 1.代表當前類的物件...
this關鍵字 static關鍵字
1.當成員變數和區域性變數重名,可以用關鍵字this來區分 this 代表物件,代表那個物件呢?當前物件 this就是所在函式所屬物件的引用 簡單說 那個物件呼叫了this所在的函式,this就代表哪個物件 this也可以用於在建構函式中呼叫其他建構函式 注意 只能定義在建構函式的第一行,因為初始化...
base關鍵字 this關鍵字
用於在派生類中實現對基類公有或者受保護成員的訪問,但是只侷限在建構函式 例項方法和例項屬性訪問器中。功能主要包括 1 呼叫基類上已被其他方法重寫的方法。2 指定建立派生類例項時應呼叫的基類建構函式。base常用於,在派生類物件初始化時和基類進行通訊。base可以訪問基類的公有成員和受保護成員,私有成...