1. 程式人生 > >學習筆記:alignas用法

學習筆記:alignas用法

structTest{
chararr[9];
alignas(16)inta;
doubleb;
charc;
};
intmain()
{
autosizeof_test=sizeof(Test);
autoalignof_test=alignof(Test);
autooffsetof_a=offsetof(Test,a);
autooffsetof_b=offsetof(Test,b);
autooffsetof_c=offsetof(Test,c);
return0;

}

問題1) 什麼是對齊。
舉例說明,某個int型別的物件,要求其儲存地址的特徵是4的整倍數。例如0x0000CC04。我們把地址值0x0000CC04除以4,餘數0,那麼這個物件的地址就是對齊的。
問題2) 為什麼要對齊。
舉例說明,對於int資料,硬體只能在4的倍數的地址讀寫,假設某int物件的地址是0x0000CC06,則硬體先讀取0x0000CC04開始的4個位元組,
取其0x0000CC06, 0x0000CC07。硬體然後讀取0x0000CC08開始的4個位元組,取其0x0000CC08, 0x0000CC09。將兩次讀取的有用資訊拼接即可。
顯然,效率不高。更嚴重的,硬體會報錯,程式執行不下去。
問題3) x86體系下,用#pragma pack(1) 改變結構體中int成員的對齊屬性,也沒報錯呀
只能說x86容忍性高,程式正常跑,不見得效率沒有降低。

問題4) C++11的alignas是什麼。

改變一個數據型別的對齊屬性。在例子中,Test::a的對齊值變成16,意味著a的地址值必須能被16整除。
考察a的偏移值是16,意味著arr[9]後面被插入填充用的7個位元組了。
問題5) 上例中,只是a相對結構體首地址的偏移值16,如果結構體首地址的值是0x0000CC01,然後+16 = 0x0000CC11,顯然不滿足地址值的16倍數對齊了在哪裡建立Test當然是很重要的,為了防止上述事件發生,需要編譯器和程式設計師的共同努力,但主要擔子還在編譯器上。例如在函式棧上建立一個Test物件,編譯器必須選擇一個好地方才行。
問題6) 為什麼sizeof(Test)是48
offsetof(a)=16,a本身長4位元組,b的偏移本應是20。
但是考慮到b的型別是double,其預設對齊值是8。20不是8的倍數,填充4個垃圾位元組,現在到達偏移值24。
所以b的真正偏移值是24,b佔8個位元組。
現在到達c,c的偏移值是32,c本身佔1個位元組,整個test的長度貌似是33。
可是你要考慮test陣列,例如陣列test kk[2]。kk[1].a, 相對於陣列首地址的偏移為33+16=49。這個地址不滿足a的對齊了。

但是在c的後面填充15個垃圾位元組,則 kk[1].a的地址 =  kk的首地址值 + kk[0]長度48 + kk[1].a偏移值16

假設編譯器把kk的首地址值放置的位置使:    kk的首地址值  /  16 = 0 kk[0]長度48 / 16 = 0
kk[1].a偏移值16 / 16 = 0
則  kk[1].a的地址 / 16 = 0 問題7) 為什麼alignof(Test)是16
由於對齊值只能是2,4,8等2的冪,所以大的對齊值一定滿足小的對齊需求。例如我按照16位元組對齊了,當然也滿足8位元組對齊,4自己對齊,2位元組對齊,1位元組對齊了。
整個結構體的對齊值,就是各成員對齊值,最大的那個。
問題8)alignas(2)inta;  可以實現嗎?
C++11規定,只能放大對齊值,而int的原始對齊值是4,現在你要求按2對齊,編譯器會忽略你的請求。
structalignas(64)Test{
//virtual~Test(){}
chararr[9];
alignas(16)inta;
doubleb;
charc;
};
問題9) 現在的test對齊值是多少?
要求Test的地址能被64整除,那麼Test本初的原始對齊值16,被棄用,使用更大的對齊值64。

問題10) 現在的test大小是多少?
Test的大小是64,增加了更多的填充垃圾位元組,以適應64倍數地址值。
問題11) C++11為什麼增加這個機制,讓程式設計師控制對齊方式。
1是現有編譯器都有語言擴充套件,例如__declspec(align(n))等,急待統一。
2是現實需求,例如利用placement new語法建立物件,如果你隨便提供的記憶體塊同T型別的對齊要求不一致,就是有副作用。
3是語言本身完善的必然,缺了這個東西,C++就不是完備的。C++是如此學院派,價值取向就是相容,獨立,完備。