——以OpenCV庫函數為例"/>
999精品在线视频,手机成人午夜在线视频,久久不卡国产精品无码,中日无码在线观看,成人av手机在线观看,日韩精品亚洲一区中文字幕,亚洲av无码人妻,四虎国产在线观看 ?

解析“指針對齊”
——以OpenCV庫函數為例

2019-04-28 05:58:14劉碩
電子技術與軟件工程 2019年3期

文/劉碩

1 內存與指針

1.1 字節

字節是內存的基本單位。一字節有八位,在內存中字節從上到下按照由低到高的順序編號(如圖1)。

1.2 字節在內存中的結構

對于內存來說,“數據”僅僅是每一個字節中的八個高低電平位的組合;而對于高級語言(如C++)來說,“數據”代表的是“對象”。由于對象的“類型”不同,一個對象儲存在一個或多個字節中。例如在64位系統中,一般情況下char類型對象占1字節,而int類型的對象要占4個字節。在C++中,讀取一個T類型對象在內存中占多少個字節是通過sizeof(T)完成的(如前所述可以得出sizeof(int)等于4)。

1.3 C++中的指針

指針是對象在內存中的地址,它的值是對應字節的編號。如果我們在C++中定義一個指向T類型對象的指針P(為了避免對指針的操作和對指針值的操作混淆,我們把指針P的值記為valueP)。那么P的含義是“內存中第valueP個字節開始,到第valueP+sizeof(T)個字節,這一段連續的內存中保存著一個T類型的對象”。

由此我們得到第一個結論:對于內存來說,數據的長度是統一的,始終是一字節;對于高級語言來說,對象的長度是根據對象的類型(如char、int)變化的,是sizeof(T)個字節。

“在某些架構下,從一個不被對象大小均勻分割的地址中讀取多字節對象是不可能(比如從32位整形中讀取4比特)。在像x86這樣的架構下,CPU通過多次讀取并從這些讀取中獲取你的值來自動處理這種情況,但代價是顯著降低了性能”——《學習OpenCV3(中文版)》為了提高效率,有必要對申請內存產生的原始指針進行處理,使指針的值能被對象長度整除(如圖2)。

1.4 讀取內存中的字節

根據指針與字節編號的關系,我們可以很自然的想到:在解引用指針時,指針所指對象的類型規定了本次解引用需要要一次讀取幾個內存單元(字節)。比如在解引用char*類型的指針時需要讀取一個字節的數據,而解引用int*類型指針時,需要一次讀取四個字節的數據。由此產生了一個不容忽視的問題——指針類型轉換時,類型大小的問題。

·較高的指針類型轉換成較低的指針類型(int* -> char*):這種轉換是安全的。只不過這樣解引用指針時,讀取的字節數會由原來的四個轉變成一個。

·較低的指針類型轉換成較高的指針類型(char* ->int*):這種轉換是危險的。因為這樣解引用指針的時候,讀取的字節個數會由原來的一個,轉變成四個。我們不能保證多被讀取的字節中是否存儲著有其他用途的數據,對這樣得到的內存加以修改,很可能引發程序運行異常。

2 內存分配與指針對齊

2.1 申請一段連續的內存

在C/C++環境下使用動態內存分配時,malloc()函數返回的值是申請到的內存資源中,第一個字節的編號,即指向一段連續的內存資源首地址的指針P。如果我們用申請得到的內存資源來存放n個T類型的對象,不能保證valueP可以被sizeof(T)整除。由此我們需要進行“指針對齊”

2.2 將指針對齊

指針對齊操作alignPtr()

(T*)(((size_t)P + n-1) & -n);

· P是malloc()返回的指針,即得到的內存資源首地址,也是需要進行對齊操作的指針。

· T是我們要存放的數據的類型(顯然T*就是ptr的類型)

· n是T類型數據所占的字節數

圖1

·“(size_t)P”這個表達式的值就是P指針的值,即valueP

·表達式的結果就是對齊之后的指針

·OpenCV源碼:

template static inline _Tp*alignPtr(

_Tp* ptr, intn=(int)sizeof(_Tp)){

CV_DbgAssert((n & (n - 1)) == 0); // n is a power of 2

return (_Tp*)(((size_t)ptr + n-1) & -n);}

情況一:分配的內存第一個字節的編號(分配內存首地址)是對象長度的整數倍。

假設編號(首地址)為0000 0100 B ,要在這段內存中存放一些長度為4的對象。則(size_t)P + n-1)等于:

0000 0100 B

+0000 0100 B

-0000 0001 B

=0000 0111 B

當n=0000 0100 B時,-n是1111 1100 B(取反加一),于是(size_t)P + n-1)&-n就是低二位置零,使得0000 0111 B變成0000 0100 B.

對比觀察得到在這種情況下,表達式的值即P的值。

情況二:分配的內存第一個字節的編號(分配內存首地址)不是是對象長度的整數倍。

假設編號(首地址)為0000 0110 B,要在這段內存中存放一些長度為4的對象,則(size_t)ptr + n-1)等于:

0000 0110 B

+0000 0100 B

-0000 0001 B

=0000 1001 B

當n=0000 0100 B時,-n是1111 1100 B(取反加一),于是(size_t)P + n-1)&-n就是去掉低二位,使得0000 1001 B變成0000 1000 B.

對比觀察可以發現這種情況下,表達式的值是P的值加一個不大于n的整數,且表達式的值可以被n整除。由“不可整除”到“可以整除”這個過程叫做“對齊”

圖2:一個T類型占4個字節,打√的編號可以被4整除

圖3

通過“對齊表達式”得到的指針所指的內存,是我們真正寫入數據的起點,而我們申請的內存是從P開始分配的。釋放內存時,也應該從P開始釋放,如何保證P和表達式的值之間的字節能夠被釋放呢?只需要在調用malloc()函數時,多申請sizeof(void *)個字節,之后將P存入這幾個字節即可,銷毀時把P從這幾個字節中讀取出來供free()函數使用。

2.3 將數據寫入內存

假設有X個T類型對象需要寫入內存,每個對象長度是sizeof(T),那么調用malloc()時,應該是malloc(sizeof(T)*x+sizeof(void*)),這樣得到的字節數量正好是x個對象和一個指針需要的空間,但是因為指針對齊時是會舍棄幾個字節不用的,這幾個字節的數量大于零且小于對象的長度,所以還要再多申請存放一個對象所需要的字節,以補充因舍棄而減少的內存空間。故調用malloc()時,參數為

Sizeof(T)*x+sizeof(void*)+sizeof(T)

*從用”sizeof(void*)”來預留一個指針所需要的字節數來看,指針的長度始終是固定的,而指針所指向的對象長度是隨著對象的類型變化的。

3 實例應用

OpenCV源碼:

·udata是調用malloc()之后得到的資源中的第一個字節編號。是一個指向資源首地址的指針,是一個未對齊的指針

·將幾個T類型的對象放入這片連續的內存,每個T類型的對象所在的地址都被一個指針所指。這些指針組成了一個指針數組adata。第一個T類型對象的地址是adata[0],第二個T類型對象的地址是adata[1]...以此類推。在我們想用T類型對象的時候可以解引用指針 *adata[index]。此外還可以用adata[-1]這個位置存儲udata的值,以便銷毀時利用。

·adata的值應該是用udata對齊后的值。因為udata是uchar*類型,而adata是uchar**類型(C++中數組名自動轉換成指向數組首地址的指針),直接帶入alignPtr()中進行對齊會有類型錯誤,所以需要強制類型轉換以滿足利用udata產生adata。強制轉換不會改變udata的值、長度。

執行fastMalloc()之后會返回adata,這時內存與指針的關系如圖3所示。

根據剛剛的分析udata和pdata之間有幾個(或者沒有)字節被閑置,不能保證是否為adata[-1]提供了足夠的字節以存放udata。因此在調用alignPtr()時,傳入的第一個參數是(uchar**)udata + 1。“(uchar**)”優先級比“+”要高,所以這個操作是“對指向指針的指針加一”。“指針加一”的操作表示“指針當前值+指針所指的對象所占的字節數”。就是說指針對齊的時候,給udata預留了sizeof(void *)個字節,保證adata前面至少有存放一個指針的空間。

4 關于指針的性質

4.1 指針的長度

根據計算機CPU的架構而定,簡單說,32位計算機的指針是32個bit組成,也就是4字節;64位計算機的指針長度是64bit組成,也就是8字節。

4.2 指針的操作

“指針加一”和“指針的值”加一是兩種情況。假設有一個指向T類型對象的指針P,P的值是valueP。P+1這個操作等價于valueP+sizeof(T)。而valueP+1是令P指針指向“當前所指的字節的”下一個字節。

主站蜘蛛池模板: 在线看国产精品| jizz国产在线| 中国国产高清免费AV片| 激情成人综合网| 欧洲成人免费视频| 国产91麻豆免费观看| 国产精品永久不卡免费视频| 国产成人高清精品免费| 亚洲黄网视频| 无码内射中文字幕岛国片| AV无码一区二区三区四区| 538国产在线| aaa国产一级毛片| 亚洲第一香蕉视频| 97免费在线观看视频| 日韩午夜伦| 亚洲区视频在线观看| 国产成人a在线观看视频| 亚洲av日韩av制服丝袜| 亚洲无限乱码一二三四区| 国产一区二区三区在线无码| 天天激情综合| 国产精品吹潮在线观看中文| 国产在线观看一区二区三区| 亚洲综合精品第一页| 国产黄在线免费观看| 国产区福利小视频在线观看尤物| 久久永久精品免费视频| 中文精品久久久久国产网址| 欧美日韩福利| 亚洲精品无码av中文字幕| 日韩欧美网址| 亚洲人成人伊人成综合网无码| 亚洲天堂网在线视频| 国产精品亚洲专区一区| 欧美日韩国产成人在线观看| 伊人久久精品无码麻豆精品| 久久a毛片| 欧美yw精品日本国产精品| 一级毛片在线播放| 日韩精品一区二区三区免费| 色综合久久无码网| h视频在线播放| 国产在线视频自拍| 国产精品大白天新婚身材| 天堂网国产| 无遮挡一级毛片呦女视频| 国产成在线观看免费视频| 五月天天天色| 一级毛片免费观看不卡视频| 欧美日韩国产在线播放| 国产精彩视频在线观看| 欧美精品一区二区三区中文字幕| 高清无码不卡视频| 久久天天躁狠狠躁夜夜躁| 波多野结衣AV无码久久一区| 精品偷拍一区二区| 欧美一区二区精品久久久| 欧美成人午夜视频免看| 久久人人妻人人爽人人卡片av| 国产成人在线无码免费视频| 国产成人久视频免费| 欧美一级专区免费大片| 在线一级毛片| 国产成人免费| 亚洲欧美日韩高清综合678| 欧美一区中文字幕| 精品国产免费观看| 毛片免费视频| 中日韩一区二区三区中文免费视频| 亚洲妓女综合网995久久| 自慰高潮喷白浆在线观看| 欧美日韩成人| 麻豆国产精品视频| 国产精品性| 日韩激情成人| 国产自视频| 91探花在线观看国产最新| 无码在线激情片| 热99re99首页精品亚洲五月天| 国产一区二区人大臿蕉香蕉| 亚洲天堂成人|