c語言記憶體重疊問題

2021-09-26 20:28:58 字數 3574 閱讀 5084

c語言關鍵字,編譯器優化時使用,不要對編譯器撒謊,如果把乙個指標定義成restrict , 編譯器會相信你,並對程式進行優化,如果出現記憶體重疊的問題,

編譯器不會替你排查。memcpy()會有記憶體重疊的問題,memove()會提前幫你檢查是否有記憶體重疊的問題。

visual studio 把函式和變數定義成 restrict 的方法不一樣。

變數 : int * __restrict

函式: __declspec(restrict) pointer_return_type

function();

__declspec(restrict) float * ma(int size)

c99中新增加了乙個型別定義,就是restrict。

概括的說,關鍵字restrict只用於限定指標;該關鍵字用於告知編譯器,所有修改該指標所指向內容的操作全部都是基於(base on)該指標的,即不存在其它進行修改操作的途徑;這樣的後果是幫助編譯器進行更好的**優化,生成更有效率的彙編**。

舉個簡單的例子

int

foo(

int* x,

int* y)

很顯然函式foo()的返回值是0,除非引數x和y的值相同。可以想象,99%的情況下該函式都會返回0而不是1。然而編譯起必須保證生成100%正確的**,因此,編譯器不能將原有**替換成下面的更優版本

intf(

int* x,

int* y)

現在我們有了restrict這個關鍵字,就可以利用它來幫助編譯器安全的進行**優化了

int f (int

*restrict x, int

*restrict y)

此時,由於指標 x 是修改 *x的唯一途徑,編譯器可以確認 「*y=1; 」這行**不會修改 *x的內容,因此可以安全的優化為

int f (int

*restrict x, int

*restrict y)

最後注意一點,restrict是c99中定義的關鍵字,c++目前並未引入;在gcc可通過使用引數」 -std=c99」 

來開啟對c99的支援

下面是我從c語言核心技術一書上摘的:

void *

memcpy

( void *

restrict dest ,

const

void *

restrict src, size_t n)

這是乙個很有用的記憶體複製函式,由於兩個引數都加了restrict限定,所以兩塊區域不能重疊,即 dest指標所指的區域,不能讓別的指標來修改,即src的指標不能修改. 相對應的別乙個函式 memmove(void *dest, const void *src, size_t)則可以重疊。

概念:

restrict,c語言中的一種型別限定符(type qualifiers),用於告訴編譯器,物件已經被指標所引用,不能通過除該指標外所有其他直接或間接的方式修改該物件的內容。

淵源:

restrict是c99標準引入的,它只可以用於限定和約束指標,並表明指標是訪問乙個資料物件的唯一且初始的方式.即它告訴編譯器,所有修改該指標所指向記憶體中內容的操作都必須通過該指標來修改,而不能通過其它途徑(其它變數或指標)來修改;這樣做的好處是,能幫助編譯器進行更好的優化**,生成更有效率的彙編**.如 int *restrict ptr, ptr 指向的記憶體單元只能被 ptr訪問到,任何同樣指向這個記憶體單元的其他指標都是未定義的,直白點就是無效指標。restrict 的出現是因為 c 語言本身固有的缺陷,c 程式設計師應當主動地規避這個缺陷,而編譯器也會很配合地優化你的**.

使用場景:

例子:

1 #include 2 

3 int foo(int *a, int *b)

4 9

10 int rfoo(int *restrict a, int *restrict b)

11 16

17 int main()

18

在gcc 8.1 下的執行結果:

不過,我有一點是疑惑的,暫時沒有想清楚,就是我在自己的ubuntu 16.04上編譯,一直是不會執行出來11的結果,感覺是這個關鍵字沒有起作用,網上查了一下沒有查到原因,請知道答案的朋友解釋一下,多謝.

1 

memcpy是c語言中的庫函式,在標頭檔案string.h中,作用是拷貝一定長度的記憶體的內容,原型分別如下:

void *

memcpy

(void *dest,

const

void *src,

size_t count)

使用memcpy時,有可能會遇到記憶體重疊的問題:

第一種情況下,拷貝重疊的區域不會出現問題,內容均可以正確的被拷貝。

第二種情況下,問題出現在右邊的兩個位元組,這兩個位元組的原來的內容首先就被覆蓋了,而且沒有儲存。所以接下來拷貝的時候,拷貝的是已經被覆蓋的內容,顯然這是有問題的。

通過memmove可以避免這一問題。memmove和memcpy實現一樣的功能:記憶體拷貝。原型如下:

void *

memmove

(void *dest,

const

void *src,

size_t count)

以下幾點你需要了解:

memove可以避免記憶體拷貝時的重疊問題。

實際上,memcpy只是memmove的乙個子集。

memcpy比memmove的速度要快一些。

有興趣的,可以看看linux的原始碼,實現很簡單,一看就明白。

/**

* memcpy - copy one area of memory to another

* @dest: where to copy to

* @src: where to copy from

* @count: the size of the area.

* * you should not use this function to access io space, use memcpy_toio()

* or memcpy_fromio() instead.

*/void *

memcpy

(void *dest,

const

void *src,

size_t count)

/**

C語言 記憶體重疊

記憶體重疊 拷貝的目的位址在源位址範圍內。所謂記憶體重疊就是拷貝的目的位址和源位址有重疊。在函式strcpy和函式memcpy都沒有對記憶體重疊做處理的,使用這兩個函式的時候只有程式設計師自己保證源位址和目標位址不重疊,或者使用memmove函式進行記憶體拷貝。memmove函式對記憶體重疊做了處理...

記憶體重疊問題

一 在記憶體拷貝時候,strcpy strncpy strcat strncat memcpy not ensure 均不允許記憶體重疊的。二 出現記憶體重疊問題的條件 1 src 在 des 的左邊 2 src size t count des至字串結束剩餘長度。解決方法 從後至前進行拷貝 src...

memcpy記憶體重疊問題

之前一直沒有注意到記憶體複製函式的記憶體重疊問題。今天偶遇遂琢磨了一下,記之。void mymemcpy void dst,const void src,size t num assert dst null src null if dst src num src dst num return dst...